
/*
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: GPL-3.0+
 * License-Filename: LICENSE
 */

#include "config.h"

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#include <gtk/gtk.h>
#include <cairo.h>
#include <cairo-pdf.h>
#include <cairo-svg.h>

#include "splay-tree.h"
#include "maingtk.h"
#include "maingtk2.h"
#include "main.h"
#include "nes.h"
#include "uniqstring.h"
#include "options.h"
#include "color.h"
#include "parse.h"
#include "folding.h"
#include "mem.h"
#include "manual.h"
#include "source.h"
#include "lmain.h"

/* draw all nodes */
extern void on_top_level_window_drawingarea1_expose_event_nodes (cairo_t * crp);

/* draw all edges */
extern void on_top_level_window_drawingarea1_expose_event_edges (cairo_t * crp);

/* draw all subgraph area */
extern void on_top_level_window_drawingarea1_expose_event_subgrapharea (cairo_t * crp);

/* where to draw */
extern GtkWidget *drawingarea1;

/* sliders */
#if GTK_HAVE_API_VERSION_2
extern GtkObject *adjvscale1;
extern GtkObject *adjvscale2;
extern GtkObject *adjhscale1;
#endif

#if GTK_HAVE_API_VERSION_3
extern GtkAdjustment *adjvscale1;
extern GtkAdjustment *adjvscale2;
extern GtkAdjustment *adjhscale1;
#endif

/* treeview window globals
 * void on_treeview_window_destroy (GtkWidget * widget, gpointer data)
 * void on_top_level_window_treeview (GtkWidget * widget, gpointer data)
 */

/* optional tree view window */
static GtkWidget *treeview_window = (GtkWidget *) 0;

/* optional tree view window text */
static GtkWidget *treeviewtext_view = NULL;

/* treeview */
static void treeview_on_changed (GtkWidget * widget, gpointer statusbar);

/* treeview */
static GtkTreeModel *treeview_create_and_fill_model (void);

/* treeview */
static void treeview_create_view_and_modell (GtkWidget * view);

/* clicked on node and center node on screen if possible */
static void treeview_center_node (struct unode *un);

/* dia output */
static void dia_string (FILE * f, char *string);

/***zzz-2***save x3d ***/

/* save as x3d output.html format */
void
on_top_level_window_saveasx3d1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *x3dfilename = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  FILE *fstream = NULL;
  struct drawn *nptr = NULL;
  struct drawe *eptr = NULL;
  char *s = NULL;
  char *sfn = NULL;
  double divx = 0.0;
  double divy = 0.0;
  double divz = 0.0;
  double zcam = 0.0;
  double length = 0.0;
  double dist = 0.0;
  double pi = 0.0;
  double r = 0.0;
  double g = 0.0;
  double b = 0.0;
  double x = 0.0;
  double y = 0.0;
  double z = 0.0;
  double x1 = 0.0;
  double x2 = 0.0;
  double y1 = 0.0;
  double y2 = 0.0;
  double z1 = 0.0;
  double z2 = 0.0;
  double dx = 0.0;
  double dy = 0.0;
  double dz = 0.0;
  double rx = 0.0;
  double ry = 0.0;
  double rz = 0.0;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }
  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As x3d output.html File",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);

  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      x3dfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (x3dfilename);
  fstream = fopen (sfn, "wb");
  /* check if open */
  if (fstream == NULL)
    {
      free (x3dfilename);
      x3dfilename = NULL;
      return;
    }

  /* scale down factor for (x,y) */
  /* fixme, this needs better tuning */
  divx = 10.0 / 5;
  divy = 25.0 / 5;
  divz = 5.0;

  /* header of x3d html file */
  fprintf (fstream, "%s\n", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
  fprintf (fstream, "%s\n", "<html>");
  fprintf (fstream, "%s\n", "<head>");
  fprintf (fstream, "%s\n", "\t<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">");
  fprintf (fstream, "%s\n", "\t<title>tuxsee 3d graph</title>");
  fprintf (fstream, "%s\n", "\t<!-- this is the javascript and css needed for x3d data -->");
  fprintf (fstream, "%s\n", "\t<script src=\"http://www.x3dom.org/download/1.5/x3dom-full.js\"></script>");
  fprintf (fstream, "%s\n", "\t<link rel=\"stylesheet\" href=\"http://www.x3dom.org/download/1.5/x3dom.css\">");
  fprintf (fstream, "%s\n", "</head>");
  fprintf (fstream, "%s\n", "<body>");
  fprintf (fstream, "<!-- Generated by %s %s -->\n", PACKAGE_STRING, PACKAGE_URL);
  fprintf (fstream, "Generated by %s at <a href=\"%s\">%s</a><br>\n", PACKAGE_STRING, PACKAGE_URL, PACKAGE_URL);
  fprintf (fstream, "%s\n", "<br>");
  fprintf (fstream, "%s\n", "<!-- start of x3d data -->");
  fprintf (fstream, "%s\n", "<x3d width='800px' height='800px'>");
  fprintf (fstream, "%s\n", "<scene>");
  /* for background color using only skycolor r/g/b as in:
   * <Background skyColor='1 0.1 0.1'/>
   * and a full background color looks like this:
   * <Background groundAngle='1.309 1.570796' groundColor='0.1 0.1 0 0.4 0.25 0.2 0.6 0.6 0.6' skyAngle='1.309 1.571' skyColor='0 0.2 0.7 0 0.5 1 1 1 1'/>
   */
  r = (double) bgcr;
  r = (r / 255.0);
  g = (double) bgcg;
  g = (g / 255.0);
  b = (double) bgcb;
  b = (b / 255.0);

  fprintf (fstream, "<!-- background color is #%02x%02x%02x -->\n", bgcr, bgcg, bgcb);
  fprintf (fstream, "<background skyColor='%f %f %f'></background>\n", r, g, b);

  /* check size of drawing in (maxx,maxy) */
  if (maxx > maxy)
    {
      zcam = (double) maxx;
    }
  else
    {
      zcam = (double) maxy;
    }

  zcam = (zcam / divx);
  zcam = (zcam * 2.0);
  if (zcam)
    {
      /* option here to set viewpoint as in
       * <viewpoint description='Book View' orientation='-1 0. 0 0.68' position='0 2.9 4.83'></viewpoint>
       */
    }

  /* drawing nodes list */
  nptr = drawnl;
  /* nodes in the drawing */
  while (nptr)
    {
      /* dummy node or real node */
      if (nptr->un->bitflags.dummynode == 1)
	{
	  /* dummy node */
	  fprintf (fstream, "<!-- dummy node \"%d\" \"%s\" -->\n", nptr->un->number, nptr->un->name);
	  fprintf (fstream, "<!-- dummy node \"%d\" indegree=%d outdegree=%d (in-out)degree=%d -->\n", nptr->un->number,
		   nptr->un->indegree, nptr->un->outdegree, (nptr->un->indegree - nptr->un->outdegree));
	  x = (double) nptr->un->x1;
	  x = (x / divx);
	  y = (double) nptr->un->y1;
	  y = (y / divy);
	  z = (double) (nptr->un->indegree - nptr->un->outdegree);
	  z = (z * divz);
	  r = (double) 0;
	  g = (double) 0;
	  b = (double) 0;
	  r = (r / 255.0);
	  g = (g / 255.0);
	  b = (b / 255.0);
	  fprintf (fstream, "<transform translation='%f %f %f'>\n", x, y, z);
	  fprintf (fstream, "%s\n", "\t<shape>");
	  fprintf (fstream, "%s\n", "\t\t<sphere radius='0.5'></sphere>");
	  fprintf (fstream, "%s\n", "\t\t<appearance>");
	  fprintf (fstream, "\t\t\t<material diffuseColor='%f %f %f'></material>\n", r, g, b);
	  fprintf (fstream, "%s\n", "\t\t</appearance>");
	  fprintf (fstream, "%s\n", "\t</shape>");
	  fprintf (fstream, "%s\n", "</transform>");
	}
      else
	{
	  fprintf (fstream, "<!-- node \"%d\" \"%s\" -->\n", nptr->un->number, nptr->un->name);
	  fprintf (fstream, "<!-- node \"%d\" indegree=%d outdegree=%d (in-out)degree=%d -->\n", nptr->un->number,
		   nptr->un->indegree, nptr->un->outdegree, (nptr->un->indegree - nptr->un->outdegree));
	  x = (double) nptr->un->x1;
	  x = (x / divx);
	  y = (double) nptr->un->y1;
	  y = (y / divy);
	  z = (double) (nptr->un->indegree - nptr->un->outdegree);
	  z = (z * divz);
	  r = (double) ((nptr->un->fillcolor & 0x00ff0000) >> 16);
	  g = (double) ((nptr->un->fillcolor & 0x0000ff00) >> 8);
	  b = (double) (nptr->un->fillcolor & 0x000000ff);
	  r = (r / 255.0);
	  g = (g / 255.0);
	  b = (b / 255.0);
	  fprintf (fstream, "<transform translation='%f %f %f'>\n", x, y, z);
	  fprintf (fstream, "%s\n", "\t<shape>");
	  fprintf (fstream, "%s\n", "\t\t<sphere radius='2.0'></sphere>");
	  fprintf (fstream, "%s\n", "\t\t<appearance>");
	  fprintf (fstream, "\t\t\t<material diffuseColor='%f %f %f'></material>\n", r, g, b);
	  fprintf (fstream, "%s\n", "\t\t</appearance>");
	  fprintf (fstream, "%s\n", "\t</shape>");
	  /* optional node label */
	  s = nptr->un->label;
	  if (s)
	    {
	      fprintf (fstream, "%s\n", "\t<transform translation='0 0 2'>");
	      fprintf (fstream, "%s\n", "\t\t<shape>");
	      fprintf (fstream, "%s\n", "\t\t\t<appearance>");
	      fprintf (fstream, "%s\n", "\t\t\t\t<material diffuseColor='0 0 0'></material>");
	      fprintf (fstream, "%s\n", "\t\t\t</appearance>");
	      fprintf (fstream, "%s", "\t\t\t<text string='\"");
	      /* copy the string until newline */
	      while (*s)
		{
		  if (*s == '\n')
		    {
		      break;
		    }
		  fputc ((int) (*s), fstream);
		  s = s + 1;
		}
	      fprintf (fstream, "%s\n", "\"' solid='false'>");
	      fprintf (fstream, "%s\n", "\t\t\t\t<fontstyle family=\"'Times' 'Orbitron'\" size=\"2.8\" style=\"BOLDITALIC\" justify=\"begin\"></fontstyle>");
	      fprintf (fstream, "%s\n", "\t\t\t</text>");
	      fprintf (fstream, "%s\n", "\t\t</shape>");
	      fprintf (fstream, "%s\n", "\t</transform>");
	    }
	  fprintf (fstream, "%s\n", "</transform>");
	}
      /* next drawing node */
      nptr = nptr->next;
    }

  /* edges list */
  eptr = drawel;

  while (eptr)
    {
      fprintf (fstream, "<!-- edge \"%d\"->\"%d\" \"%s\"->\"%s\" -->\n", eptr->ue->fn->number, eptr->ue->tn->number, eptr->ue->fn->name, eptr->ue->tn->name);
      x1 = (double) eptr->ue->fn->x1;
      x1 = (x1 / divx);
      y1 = (double) eptr->ue->fn->y1;
      y1 = (y1 / divy);
      z1 = (double) (eptr->ue->fn->indegree - eptr->ue->fn->outdegree);
      z1 = (z1 * divz);
      x2 = (double) eptr->ue->tn->x1;
      x2 = (x2 / divx);
      y2 = (double) eptr->ue->tn->y1;
      y2 = (y2 / divy);
      z2 = (double) (eptr->ue->tn->indegree - eptr->ue->tn->outdegree);
      z2 = (z2 * divz);
      dx = (x1 - x2);
      dy = (y1 - y2);
      dz = (z1 - z2);
      length = sqrt ((dx * dx) + (dy * dy) + (dz * dz));
      rx = dx;
      ry = (dy + length);
      rz = dz;
      dist = sqrt ((pow (fabs (rx), 2.0)) + (pow (fabs (ry), 2.0)));
      dist = sqrt ((pow (fabs (rz), 2.0)) + (pow (fabs (dist), 2.0)));
      if (dist > 0)
	{
	  rx = (rx / dist);
	  ry = (ry / dist);
	  rz = (rz / dist);
	}
      else
	{

	  fprintf (fstream, "<!-- dist is %f and setting r(%f,%f,%f) to r(0,0,0) -->\n", dist, rx, ry, rz);
	  rx = 0.0;
	  ry = 0.0;
	  rz = 0.0;
	}

      pi = 3.14159265358979;
      r = (double) ((eptr->ue->color & 0x00ff0000) >> 16);
      g = (double) ((eptr->ue->color & 0x0000ff00) >> 8);
      b = (double) (eptr->ue->color & 0x000000ff);
      r = (r / 255.0);
      g = (g / 255.0);
      b = (b / 255.0);
      fprintf (fstream, "<transform translation='%f %f %f' rotation='%f %f %f %f'>\n", (x1 - (dx / 2)), (y1 - (dy / 2)), (z1 - (dz / 2)), rx, ry, rz, pi);
      fprintf (fstream, "%s\n", "\t<shape>");
      fprintf (fstream, "\t\t<cylinder bottom='true' radius='0.1' side='true' top='false' height='%f'></cylinder>\n", length);
      fprintf (fstream, "%s\n", "\t\t<appearance>");
      fprintf (fstream, "\t\t\t<material diffuseColor='%f %f %f'></material>\n", r, g, b);
      fprintf (fstream, "%s\n", "\t\t</appearance>");
      fprintf (fstream, "%s\n", "\t</shape>");
      fprintf (fstream, "%s\n", "</transform>");
      /* next edge */
      eptr = eptr->next;
    }

  /* tail of x3d html file */
  fprintf (fstream, "%s\n", "</scene>");
  fprintf (fstream, "%s\n", "</x3d>");
  fprintf (fstream, "%s\n", "<!-- end of x3d data -->");
  fprintf (fstream, "%s\n", "</body>");
  fprintf (fstream, "%s\n", "</html>");

  /* x3d data can be extended with arrows, splines, click-on-nodes, javascript, images */

  /* ready */
  fclose (fstream);

  /* */
  free (x3dfilename);
  x3dfilename = NULL;

  return;
}


/* save as vrml output.wrl format */
void
on_top_level_window_saveasvrml1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *vrmlfilename = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  FILE *fstream = NULL;
  struct drawn *nptr = NULL;
  struct drawe *eptr = NULL;
  char *s = NULL;
  char *sfn = NULL;
  double div = 0.0;
  double zcam = 0.0;
  double length = 0.0;
  double dist1 = 0.0;
  double dist = 0.0;
  double pi = 0.0;
  double r = 0.0;
  double g = 0.0;
  double b = 0.0;
  double x = 0.0;
  double y = 0.0;
  double z = 0.0;
  double x1 = 0.0;
  double x2 = 0.0;
  double y1 = 0.0;
  double y2 = 0.0;
  double z1 = 0.0;
  double z2 = 0.0;
  double dx = 0.0;
  double dy = 0.0;
  double dz = 0.0;
  double rx = 0.0;
  double ry = 0.0;
  double rz = 0.0;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }
  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As vrml output.wrl File",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);

  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      vrmlfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (vrmlfilename);
  fstream = fopen (sfn, "wb");
  /* check if open */
  if (fstream == NULL)
    {
      free (vrmlfilename);
      vrmlfilename = NULL;
      return;
    }

  /* divide x,y by this factor */
  div = 10.0;
  /* header of wrl file */
  fprintf (fstream, "%s\n", "#VRML V2.0 utf8");
  fprintf (fstream, "%s\n", "");
  fprintf (fstream, "# Generated by %s %s\n", PACKAGE_STRING, PACKAGE_URL);
  fprintf (fstream, "%s\n", "# tested with the program lookat from openwrl.org");
  fprintf (fstream, "%s\n", "# does not work with blender from blender.org");
  fprintf (fstream, "%s\n", "");
  r = (double) bgcr;
  r = (r / 255.0);
  g = (double) bgcg;
  g = (g / 255.0);
  b = (double) bgcb;
  b = (b / 255.0);
  fprintf (fstream, "# background color is #%02x%02x%02x\n", bgcr, bgcg, bgcb);
  fprintf (fstream, "%s\n", "Background {");
  fprintf (fstream, "\tskyColor %f %f %f\n", r, g, b);
  fprintf (fstream, "%s\n", "}");
  fprintf (fstream, "%s\n", "");
  if (maxx > maxy)
    {
      zcam = (double) maxx;
    }
  else
    {
      zcam = (double) maxy;
    }

  zcam = (zcam / div);
  zcam = (zcam * 2.0);
  fprintf (fstream, "# drawing size is (%d,%d)\n", maxx, maxy);
  fprintf (fstream, "%s\n", "Viewpoint {");
  fprintf (fstream, "\tposition 0 0 %f\n", zcam);
  fprintf (fstream, "%s\n", "}");
  fprintf (fstream, "%s\n", "");
  fprintf (fstream, "%s\n", "WorldInfo {");
  fprintf (fstream, "\tinfo [\"Generated by %s %s\"]\n", PACKAGE_STRING, PACKAGE_URL);
  fprintf (fstream, "%s\n\n", "}");
  /* drawing nodes list */
  nptr = drawnl;
  /* nodes in the drawing */
  while (nptr)
    {
      /* dummy node or real node */
      if (nptr->un->bitflags.dummynode == 1)
	{
	  /* dummy node */
	  fprintf (fstream, "# dummy node \"%d\" \"%s\"\n", nptr->un->number, nptr->un->name);
	  fprintf (fstream, "# dummynode \"%d\" indegree=%d outdegree=%d (in-out)degree=%d\n", nptr->un->number,
		   nptr->un->indegree, nptr->un->outdegree, (nptr->un->indegree - nptr->un->outdegree));
	  x = (double) nptr->un->x1;
	  x = (x / div);
	  y = (double) nptr->un->y1;
	  y = (y / div);
	  z = (double) (nptr->un->indegree - nptr->un->outdegree);
	  z = z * 25.0;
	  fprintf (fstream, "%s\n", "Transform {");
	  fprintf (fstream, "\ttranslation %f %f %f\n", x, y, z);
	  fprintf (fstream, "%s\n", "\tchildren [");
	  fprintf (fstream, "%s\n", "\t\tShape {");
	  fprintf (fstream, "%s\n", "\t\t\tappearance Appearance {");
	  fprintf (fstream, "%s\n", "\t\t\t\tmaterial Material {");
	  r = (double) 0;
	  g = (double) 0;
	  b = (double) 0;
	  r = (r / 255.0);
	  g = (g / 255.0);
	  b = (b / 255.0);
	  fprintf (fstream, "\t\t\t\t\tdiffuseColor %f %f %f\n", r, g, b);
	  fprintf (fstream, "%s\n", "\t\t\t\t}");
	  fprintf (fstream, "%s\n", "\t\t\t}");
	  fprintf (fstream, "%s\n", "\t\t\tgeometry Sphere { radius 0.5 }");
	  fprintf (fstream, "%s\n", "\t\t}");
	  fprintf (fstream, "%s\n", "\t]");
	  fprintf (fstream, "%s\n\n", "}");
	}
      else
	{
	  fprintf (fstream, "# node \"%d\" \"%s\"\n", nptr->un->number, nptr->un->name);
	  fprintf (fstream, "# node \"%d\" indegree=%d outdegree=%d (in-out)degree=%d\n", nptr->un->number, nptr->un->indegree,
		   nptr->un->outdegree, (nptr->un->indegree - nptr->un->outdegree));
	  x = (double) nptr->un->x1;
	  x = (x / div);
	  y = (double) nptr->un->y1;
	  y = (y / div);
	  z = (double) (nptr->un->indegree - nptr->un->outdegree);
	  z = z * 25.0;
	  fprintf (fstream, "%s\n", "Transform {");
	  fprintf (fstream, "\ttranslation %f %f %f\n", x, y, z);
	  fprintf (fstream, "%s\n", "\tchildren [");
	  fprintf (fstream, "%s\n", "\t\tShape {");
	  fprintf (fstream, "%s\n", "\t\t\tappearance Appearance {");
	  fprintf (fstream, "%s\n", "\t\t\t\tmaterial Material {");
	  r = (double) ((nptr->un->fillcolor & 0x00ff0000) >> 16);
	  g = (double) ((nptr->un->fillcolor & 0x0000ff00) >> 8);
	  b = (double) (nptr->un->fillcolor & 0x000000ff);
	  r = (r / 255.0);
	  g = (g / 255.0);
	  b = (b / 255.0);
	  fprintf (fstream, "\t\t\t\t\tdiffuseColor %f %f %f\n", r, g, b);
	  fprintf (fstream, "%s\n", "\t\t\t\t}");
	  fprintf (fstream, "%s\n", "\t\t\t}");
	  fprintf (fstream, "%s\n", "\t\t\tgeometry Sphere { radius 2 }");
	  fprintf (fstream, "%s\n", "\t\t}");
	  fprintf (fstream, "%s\n", "\t]");
	  fprintf (fstream, "%s\n\n", "}");
	  s = nptr->un->label;
	  fprintf (fstream, "\n");
	  /* label at (x+2) */
	  if (s)
	    {
	      fprintf (fstream, "# node \"%d\" \"%s\" label text\n", nptr->un->number, nptr->un->name);
	      fprintf (fstream, "%s\n", "Transform {");
	      fprintf (fstream, "\ttranslation %f %f %f\n", (x + 2), y, z);
	      fprintf (fstream, "%s\n", "\tchildren [");
	      fprintf (fstream, "%s\n", "\t\tBillboard {");
	      fprintf (fstream, "%s\n", "\t\t\taxisOfRotation 0.0 0.0 0.0");
	      fprintf (fstream, "%s\n", "\t\t\t\tchildren [");
	      fprintf (fstream, "%s\n", "\t\t\t\t\tShape {");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\tappearance Appearance {");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\t\tmaterial Material { diffuseColor 0.0 0.0 0.0 }");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\t}");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\tgeometry Text {");
	      fprintf (fstream, "%s", "\t\t\t\t\t\t\tstring \"");
	      /* copy the string until newline */
	      while (*s)
		{
		  if (*s == '\n')
		    {
		      break;
		    }
		  fputc ((int) (*s), fstream);
		  s = s + 1;
		}
	      fprintf (fstream, "%s\n", "\"");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\t\tfontStyle FontStyle {");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\t\tfamily \"SANS\"");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\t\tstyle \"BOLD\"");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\t\tjustify \"LEFT\"");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\t\tsize 4");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t\t}");
	      fprintf (fstream, "%s\n", "\t\t\t\t\t}");
	      fprintf (fstream, "%s\n", "\t\t\t\t}");
	      fprintf (fstream, "%s\n", "\t\t\t]");
	      fprintf (fstream, "%s\n", "\t\t}");
	      fprintf (fstream, "%s\n", "\t]");
	      fprintf (fstream, "%s\n", "}");
	      fprintf (fstream, "\n");
	    }
	}
      /* next drawing node */
      nptr = nptr->next;
    }

  /* edges list */
  eptr = drawel;
  /* edges in the drawing */
  if (eptr)
    {
      while (eptr)
	{
	  fprintf (fstream,
		   "# edge \"%d\"->\"%d\" \"%s\" (%d,%d) -> \"%s\" (%d,%d)\n", eptr->ue->fn->number, eptr->ue->tn->number,
		   eptr->ue->fn->name, eptr->ue->fn->x1, eptr->ue->fn->y1, eptr->ue->tn->name, eptr->ue->tn->x1, eptr->ue->tn->y1);
	  /* from node (x,y,z) */
	  x1 = (double) eptr->ue->fn->x1;
	  x1 = (x1 / div);
	  y1 = (double) eptr->ue->fn->y1;
	  y1 = (y1 / div);
	  z1 = (double) (eptr->ue->fn->indegree - eptr->ue->fn->outdegree);
	  z1 = (z1 * 25.0);
	  /* to node (x,y,z) */
	  x2 = (double) eptr->ue->tn->x1;
	  x2 = (x2 / div);
	  y2 = (double) eptr->ue->tn->y1;
	  y2 = (y2 / div);
	  z2 = (double) (eptr->ue->tn->indegree - eptr->ue->tn->outdegree);
	  z2 = (z2 * 25.0);
	  /* delta (x,y,z) */
	  dx = x1 - x2;
	  dy = y1 - y2;
	  dz = z1 - z2;
	  /* len of vector */
	  length = sqrt ((dx * dx) + (dy * dy) + (dz * dz));
	  /* rotation */
	  rx = dx;
	  ry = (dy + length);
	  rz = dz;
	  /* calculate dist */
	  dist1 = sqrt ((pow (fabs (rx), 2.0)) + (pow (fabs (ry), 2.0)));
	  dist = sqrt ((pow (fabs (rz), 2.0)) + (pow (fabs (dist1), 2.0)));
	  /* check dist */
	  if (dist > 0)
	    {
	      rx = (rx / dist);
	      ry = (ry / dist);
	      rz = (rz / dist);
	    }
	  else
	    {
	      /* todo dist should not be 0 */
	      fprintf (fstream, "# dist is %f dist1 is %f and setting r(%f,%f,%f) to r(0,0,0) d(%f,%f,%f) len %f\n", dist,
		       dist1, rx, ry, rz, dx, dy, dz, length);
	      rx = 0.0;
	      ry = 0.0;
	      rz = 0.0;
	    }

	  /* phi */
	  pi = 3.14159265358979;
	  /* edge color */
	  r = (double) ((eptr->ue->color & 0x00ff0000) >> 16);
	  g = (double) ((eptr->ue->color & 0x0000ff00) >> 8);
	  b = (double) (eptr->ue->color & 0x000000ff);
	  r = (r / 255.0);
	  g = (g / 255.0);
	  b = (b / 255.0);
	  fprintf (fstream, "%s", "Transform {\n");
	  fprintf (fstream, "\ttranslation %f %f %f\n", (x1 - (dx / 2)), (y1 - (dy / 2)), (z1 - (dz / 2)));
	  fprintf (fstream, "\trotation %f %f %f %f\n", rx, ry, rz, pi);
	  fprintf (fstream, "%s\n", "\tchildren [");
	  fprintf (fstream, "%s\n", "\t\tShape {");
	  fprintf (fstream, "%s\n", "\t\t\tappearance Appearance {");
	  fprintf (fstream, "%s\n", "\t\t\t\tmaterial Material {");
	  fprintf (fstream, "\t\t\t\t\tdiffuseColor %f %f %f\n", r, g, b);
	  fprintf (fstream, "%s\n", "\t\t\t\t}");
	  fprintf (fstream, "%s\n", "\t\t\t}");
	  fprintf (fstream, "%s\n", "\t\t\tgeometry Cylinder {");
	  fprintf (fstream, "%s\n", "\t\t\t\tradius 0.2");
	  fprintf (fstream, "\t\t\t\theight %f\n", length);
	  fprintf (fstream, "%s\n", "\t\t\t\ttop FALSE");
	  fprintf (fstream, "%s\n", "\t\t\t\tbottom FALSE");
	  fprintf (fstream, "%s\n", "\t\t\t}");
	  fprintf (fstream, "%s\n", "\t\t}");
	  fprintf (fstream, "%s\n", "\t\t]");
	  fprintf (fstream, "%s\n", "}");
	  fprintf (fstream, "\n");
	  /* next edge */
	  eptr = eptr->next;
	}
    }

  /* tail of wrl file */
  fprintf (fstream, "%s\n", "# /* end */");
  /* ready */
  fclose (fstream);
  /* */
  free (vrmlfilename);
  vrmlfilename = NULL;
  return;
}

/***zz0***save dot ***/

/* save as dot format */
void
on_top_level_window_saveasdot1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *dotfilename = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  FILE *fstream = NULL;
  struct drawn *nptr = NULL;
  struct drawe *eptr = NULL;
  int ana = 0;
  char *s = NULL;
  char *sfn = NULL;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }
  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As dot",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);

  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      dotfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (dotfilename);
  fstream = fopen (sfn, "wb");
  /* check if open */
  if (fstream == NULL)
    {
      free (dotfilename);
      dotfilename = NULL;
      return;
    }

  /* header of dot file */
  fprintf (fstream, "/* generated by %s %s */\n", PACKAGE_STRING, PACKAGE_URL);
  fprintf (fstream, "%s\n", "digraph \"tuxsee\" {");
  /* drawing nodes list */
  nptr = drawnl;
  /* nodes in the drawing */
  while (nptr)
    {
      /* dummy node or real node */
      if (nptr->un->bitflags.dummynode == 1)
	{
	  /* dummy node */
	  fprintf (fstream, " \"%d\" [label=\"\", shape=\"point\"];\n", nptr->un->number);
	}
      else
	{
	  fprintf (fstream, " \"%d\" ", nptr->un->number);
	  s = nptr->un->label;
	  if (s == NULL)
	    {
	      fprintf (fstream, "%s", "[label=\"\"");
	    }
	  else
	    {
	      fprintf (fstream, "%s", "[label=\"");
	      while (*s)
		{
		  if (*s == '"')
		    {
		      fputc ('\\', fstream);
		      fputc ('"', fstream);
		    }
		  else if (*s == '\n')
		    {
		      fputc ('\\', fstream);
		      fputc ('n', fstream);
		    }
		  else
		    {
		      /* literally in the string */
		      fputc (*s, fstream);
		    }
		  s++;
		}
	      fputc ('"', fstream);
	    }
	  if (nptr->un->fillcolor)
	    {
	      fprintf (fstream, ", style=\"filled\", fillcolor=\"#%02x%02x%02x\"", ((nptr->un->fillcolor & 0x00ff0000) >> 16),
		       ((nptr->un->fillcolor & 0x0000ff00) >> 8), (nptr->un->fillcolor & 0x000000ff));
	    }
	  /* end of node [...] */
	  fprintf (fstream, "%s\n", "];");
	}
      /* next drawing node */
      nptr = nptr->next;
    }

  /* edges list */
  eptr = drawel;
  /* edges in the drawing */
  if (eptr)
    {
      while (eptr)
	{
	  ana = 0;
	  if (eptr->ue->bitflags.reversed == 0)
	    {
	      /* regular edge */
	      fprintf (fstream, " \"%d\" -> \"%d\"", eptr->ue->fn->number, eptr->ue->tn->number);
	      /* no arrow at dummy node */
	      if (eptr->ue->tn->label == NULL)
		{
		  ana = 1;
		}
	    }
	  else
	    {
	      /* reversed edge */
	      fprintf (fstream, " \"%d\" -> \"%d\"", eptr->ue->tn->number, eptr->ue->fn->number);
	      /* no arrow at dummy node */
	      if (eptr->ue->fn->label == NULL)
		{
		  ana = 1;
		}
	    }
	  /* edge options */
	  fprintf (fstream, "%s", " [");
	  if (ana)
	    {
	      fprintf (fstream, "%s", "arrowhead=\"none\", ");
	    }
	  if (eptr->ue->color)
	    {
	      fprintf (fstream, "color=\"#%02x%02x%02x\", ", ((eptr->ue->color & 0x00ff0000) >> 16),
		       ((eptr->ue->color & 0x0000ff00) >> 8), (eptr->ue->color & 0x000000ff));
	    }
	  if (eptr->ue->bitflags.style == ESTYLE_DASHED)
	    {
	      fprintf (fstream, "%s", "style=\"dashed\"");
	    }
	  else if (eptr->ue->bitflags.style == ESTYLE_DOTTED)
	    {
	      fprintf (fstream, "%s", "style=\"dotted\"");
	    }
	  else if (eptr->ue->bitflags.style == ESTYLE_INVIS)
	    {
	      fprintf (fstream, "%s", "style=\"invis\"");
	    }
	  else
	    {
	      fprintf (fstream, "%s", "style=\"solid\"");
	    }
	  fprintf (fstream, "%s\n", "];");
	  /* next edge */
	  eptr = eptr->next;
	}
    }

  /* tail of dot file */
  fprintf (fstream, "%s\n", "} /* end */");
  /* data can be extended to improve drawing */
  /* ready */
  fclose (fstream);
  /* */
  free (dotfilename);
  dotfilename = NULL;
  return;
}

/***zz2***save dia ***/

/*
 * There are 5 pre-defined entity references in XML:
 * &lt; 	< 	less than
 * &gt; 	> 	greater than
 * &amp; 	& 	ampersand 
 * &apos; 	' 	apostrophe
 * &quot; 	" 	quotation mark
 * This is what dia uses for <>"'&#
 * <dia:string>#&lt;&gt;"'&amp;##</dia:string>
 */
static void
dia_string (FILE * f, char *string)
{
  char *p = NULL;
  if (string == NULL)
    {
      return;
    }

  p = string;
  while (*p)
    {
      if (*p == '#')
	{
	  /* dia uses # for # */
	  fputc ('#', f);
	}
      else if (*p == '\'')
	{
	  /* dia uses ' for ' */
	  fputc ('\'', f);
	}
      else if (*p == '"')
	{
	  /* dia uses " for " */
	  fputc ('"', f);
	}
      else if (*p == '<')
	{
	  /* dia uses xml < for < */
	  fputs ("&lt;", f);
	}
      else if (*p == '>')
	{
	  /* dia uses xml > for > */
	  fputs ("&gt;", f);
	}
      else if (*p == '&')
	{
	  /* dia uses xml & for & */
	  fputs ("amp;", f);
	}
      else
	{
	  fputc (*p, f);
	}
      p++;
    }

  return;
}

/* save as dia software xml format.
 * thgere is no documentation on thix xml format.
 * read dia source, guess and look at xml data.
 * java api for dia xml https://v2.pikacode.com/tachikoma/diaxml_api
*/
void
on_top_level_window_saveasdia1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *diafilename = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  FILE *f = NULL;
  int level = 0;
  struct drawn *dptr = NULL;
  int red = 0;
  int blue = 0;
  int green = 0;
  double diafactor = 10.0;
  int objectcount = 0;
  struct dli *lp = NULL;
  struct dde *deptr = NULL;
  int multarrows = 0;
  double fnx1 = 0.0;
  double fny2 = 0.0;
  double flhny = 0.0;
  double tny0 = 0.0;
  double tnx1 = 0.0;
  double tny1 = 0.0;
  char *sfn = NULL;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }
  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As dia",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);

  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      diafilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (diafilename);
  f = fopen (sfn, "wb");
  /* check if open */
  if (f == NULL)
    {
      free (diafilename);
      diafilename = NULL;
      return;
    }

  /* scaling factor */
  diafactor = 10.0;
  /* uniq object counter */
  objectcount = 0;
  /* head */
  fprintf (f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
  fprintf (f, "<dia:diagram xmlns:dia=\"http://www.lysator.liu.se/~alla/dia/\">\n");
  fprintf (f, "<dia:layer name=\"Background\" visible=\"true\" active=\"true\">\n");
  fprintf (f, "<!-- generated by %s %s -->\n", PACKAGE_STRING, PACKAGE_URL);
  /* all nodes in all levels */
  dptr = drawnl;
  while (dptr)
    {
      if (dptr->un->label)
	{
	  /* regular node or edge label */
	  fprintf (f, "<!-- node %s in drawing at (%d,%d) size (%d,%d) relative level=%d -->\n", dptr->un->name, dptr->un->x0,
		   dptr->un->y1, dptr->un->bbx, dptr->un->bby, dptr->un->level);
	  fprintf (f, "<dia:object type=\"Standard - Box\" version=\"0\" id=\"O%d\">\n", objectcount);
	  /* dia object number to reference in edge */
	  dptr->un->objectnr = objectcount;
	  objectcount = objectcount + 1;
	  fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	  fprintf (f, "<dia:point val=\"%f,%f\"/>\n", dptr->un->x0 / diafactor, dptr->un->y1 / diafactor);
	  fprintf (f, "</dia:attribute>\n");
	  fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	  fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", dptr->un->x0 / diafactor, dptr->un->y1 / diafactor,
		   (dptr->un->x0 + dptr->un->bbx) / diafactor, (dptr->un->y1 + dptr->un->bby) / diafactor);
	  fprintf (f, "</dia:attribute>\n");
	  fprintf (f, "<dia:attribute name=\"elem_corner\">\n");
	  fprintf (f, "<dia:point val=\"%f,%f\"/>\n", dptr->un->x0 / diafactor, dptr->un->y1 / diafactor);
	  fprintf (f, "</dia:attribute>\n");
	  fprintf (f, "<dia:attribute name=\"elem_width\">\n");
	  fprintf (f, "<dia:real val=\"%f\"/>\n", dptr->un->bbx / diafactor);
	  fprintf (f, "</dia:attribute>\n");
	  fprintf (f, "<dia:attribute name =\"elem_height\">\n");
	  fprintf (f, "<dia:real val=\"%f\"/>\n", dptr->un->bby / diafactor);
	  fprintf (f, "</dia:attribute>\n");
	  red = (dptr->un->fillcolor & 0x00ff0000) >> 16;
	  green = (dptr->un->fillcolor & 0x0000ff00) >> 8;
	  blue = (dptr->un->fillcolor & 0x000000ff);
	  fprintf (f, "<dia:attribute name=\"inner_color\">\n");
	  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
	  fprintf (f, "</dia:attribute>\n");
	  fprintf (f, "<dia:attribute name=\"show_background\">\n");
	  fprintf (f, "<dia:boolean val=\"true\"/>\n");
	  fprintf (f, "</dia:attribute>\n");
	  fprintf (f, "</dia:object>\n");
	  fprintf (f, "<dia:object type=\"Standard - Text\" version=\"1\" id=\"O%d\">\n", objectcount);
	  objectcount = objectcount + 1;
	  fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	  fprintf (f, "<dia:point val=\"%f,%f\"/>\n", dptr->un->x0 / diafactor, dptr->un->y1 / diafactor);
	  fprintf (f, "</dia:attribute>\n");
	  /*
	   * fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	   * fprintf (f,"<dia:rectangle val=\"13.7,0.186375;14.5336,0.98725\"/>\n");
	   * fprintf (f, "</dia:attribute>\n");
	   */
	  fprintf (f, "<dia:attribute name=\"text\">\n");
	  fprintf (f, "<dia:composite type=\"text\">\n");
	  fprintf (f, "<dia:attribute name=\"string\">\n");
	  fprintf (f, "<dia:string>#");
	  dia_string (f, dptr->un->label);
	  fprintf (f, "#</dia:string>\n");
	  fprintf (f, "</dia:attribute>\n");
	  /* <dia:attribute name="font"> */
	  /* <dia:font family="sans" style="0" name="Helvetica"/> */
	  /* </dia:attribute> */
	  /* <dia:attribute name="height"> */
	  /* <dia:real val="0.80000000000000004"/> */
	  /* </dia:attribute> */
	  /* <dia:attribute name="pos"> */
	  /* <dia:point val="13.7,0.8"/> */
	  /* </dia:attribute> */
	  /* <dia:attribute name="color"> */
	  /* <dia:color val="#000000"/> */
	  /* </dia:attribute> */
	  /* <dia:attribute name="alignment"> */
	  /* <dia:enum val="0"/> */
	  /* </dia:attribute> */
	  fprintf (f, "</dia:composite>\n");
	  fprintf (f, "</dia:attribute>\n");
	  /* <dia:attribute name="valign"> */
	  /* <dia:enum val="3"/> */
	  /* </dia:attribute> */
	  /*
	   * fprintf (f, "<dia:connections>\n");
	   * fprintf (f, "<dia:connection handle=\"0\" to=\"O%d\" connection=\"8\"/>\n", objectcount - 1);
	   * fprintf (f, "</dia:connections>\n");
	   */
	  fprintf (f, "</dia:object>\n");
	}
      else
	{
	  /* dummy node without label */
	}
      dptr = dptr->next;
    }


  /* draw edges in all levels */
  for (level = 0; level < dli_nlevels; level++)
    {
      /* choose level */
      lp = dlip[level];
      lp->draw = 1;
    }

  for (level = 0; level < dli_nlevels; level++)
    {
      /* choose level */
      lp = dlip[level];
      /* scan edges in layer */
      deptr = lp->el;
      while (deptr)
	{

	  /* skip edge if both nodes are not draw */
	  if ((dlip[deptr->de->ue->fn->level]->draw == 0) && (dlip[deptr->de->ue->tn->level]->draw == 0))
	    {
	      deptr = deptr->next;
	      continue;
	    }

	  /* check for invisible edge */
	  if (deptr->de->ue->bitflags.style == ESTYLE_INVIS)
	    {
	      /* invisible edge and do not draw edge */
	      deptr = deptr->next;
	      continue;
	    }


	  /* multiple arrows for long edges */
	  multarrows = deptr->de->ue->bitflags.multarrows;
	  /* override if option is set */
	  if (option_multi_arrows)
	    {
	      multarrows = 1;
	    }

	  /* describe edge in xml */
	  fprintf (f, "%s", "<!-- edge from node \"");
	  dia_string (f, deptr->de->ue->fn->name);
	  fprintf (f, "%s", "\" to \"");
	  dia_string (f, deptr->de->ue->tn->name);
	  fprintf (f, "%s\n", "\" -->");
	  /* no spline edges but straight point to point */
	  /* calculate some points */
	  fnx1 = deptr->de->ue->fn->x1 / diafactor;
	  fny2 = deptr->de->ue->fn->y2 / diafactor;
	  flhny = (dlip[deptr->de->ue->fn->level]->y0 + dlip[deptr->de->ue->fn->level]->hn) / diafactor;
	  tny0 = dlip[deptr->de->ue->tn->level]->y0 / diafactor;
	  tnx1 = deptr->de->ue->tn->x1 / diafactor;
	  tny1 = deptr->de->ue->tn->y1 / diafactor;
	  /* regular edges */
	  if (deptr->de->ue->fn->bitflags.dummynode == 0 && deptr->de->ue->tn->bitflags.dummynode == 0)
	    {
	      /* from real node to real node */
	      if ((deptr->de->ue->bitflags.arrows == 1) && ((deptr->de->ue->bitflags.reversed == 1) || (deptr->de->ue->bitflags.botharrows == 1)))
		{
		  /* draw arrow at from node but not at edge label node */
		  if (deptr->de->ue->fn->bitflags.edgelabel == 0)
		    {
		      /* if the from-line is too short use longer */
		      if ((flhny - fny2) < 4)
			{
			}
		      else
			{
			}
		    }
		}

	      /* draw edge lines */

	      /*
	       * cairo_move_to (crp, fnx1, fny2);
	       * cairo_line_to (crp, fnx1, flhny);
	       * cairo_line_to (crp, tnx1, tny0);
	       * cairo_line_to (crp, tnx1, tny1);
	       */

	      /* cairo_move_to (crp, fnx1, fny2); cairo_line_to (crp, fnx1, flhny); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, fny2, fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      /* connect at south of from node */
	      fprintf (f, "<dia:connections>\n");
	      fprintf (f, "<dia:connection handle=\"0\" to=\"O%d\" connection=\"6\"/>\n", deptr->de->ue->fn->objectnr);
	      fprintf (f, "</dia:connections>\n");
	      fprintf (f, "</dia:object>\n");
	      /* cairo_line_to (crp, fnx1, flhny); cairo_line_to (crp, tnx1, tny0); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, flhny, tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      fprintf (f, "</dia:object>\n");
	      /* cairo_line_to (crp, tnx1, tny0); cairo_line_to (crp, tnx1, tny1); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", tnx1, tny0, tnx1, tny1);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny1);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      /* connect at north of to node */
	      fprintf (f, "<dia:connections>\n");
	      fprintf (f, "<dia:connection handle=\"0\" to=\"O%d\" connection=\"1\"/>\n", deptr->de->ue->tn->objectnr);
	      fprintf (f, "</dia:connections>\n");
	      fprintf (f, "</dia:object>\n");
	      /* draw arrow at to node */
	      if ((deptr->de->ue->bitflags.arrows == 1) && ((deptr->de->ue->bitflags.reversed == 0) || (deptr->de->ue->bitflags.botharrows == 1)))
		{
		  /* draw arrow at to node but not at edge label node */
		  if (deptr->de->ue->tn->bitflags.edgelabel == 0)
		    {
		      if ((tny1 - tny0) < 4)
			{
			}
		      else
			{
			}
		    }
		}
	    }
	  else if (deptr->de->ue->fn->bitflags.dummynode == 0 && deptr->de->ue->tn->bitflags.dummynode == 1)
	    {
	      /* from real node to dummy node */
	      if ((deptr->de->ue->bitflags.arrows == 1) && ((deptr->de->ue->bitflags.reversed == 1) || (deptr->de->ue->bitflags.botharrows == 1)))
		{
		  /* draw arrow at from node but not at edge label node */
		  if (deptr->de->ue->fn->bitflags.edgelabel == 0)
		    {
		      /* if the from-line is too short use longer */
		      if ((flhny - fny2) < 4)
			{
			}
		      else
			{
			}
		    }
		}

	      /* draw edge lines */

	      /*
	       * cairo_move_to (crp, fnx1, fny2);
	       * cairo_line_to (crp, fnx1, flhny);
	       * cairo_line_to (crp, tnx1, tny0);
	       * cairo_line_to (crp, tnx1, tny1);
	       */

	      /* cairo_move_to (crp, fnx1, fny2); cairo_line_to (crp, fnx1, flhny); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, fny2, fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      /* connect at south of from node */
	      fprintf (f, "<dia:connections>\n");
	      fprintf (f, "<dia:connection handle=\"0\" to=\"O%d\" connection=\"6\"/>\n", deptr->de->ue->fn->objectnr);
	      fprintf (f, "</dia:connections>\n");
	      fprintf (f, "</dia:object>\n");
	      /* cairo_line_to (crp, fnx1, flhny); cairo_line_to (crp, tnx1, tny0); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, flhny, tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      fprintf (f, "</dia:object>\n");
	      /* cairo_line_to (crp, tnx1, tny0); cairo_line_to (crp, tnx1, tny1); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", tnx1, tny0, tnx1, tny1);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny1);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      fprintf (f, "</dia:object>\n");
	      /* check for multiple arrows also at dummy nodes */
	      if ((deptr->de->ue->bitflags.arrows == 1) && (multarrows == 1))
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, fny2, fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

		{
		  if (deptr->de->ue->bitflags.reversed == 1)
		    {
		      /* up arrow */
		    }
		  else
		    {
		      /* down arrow */
		    }
		}
	    }
	  else if (deptr->de->ue->fn->bitflags.dummynode == 1 && deptr->de->ue->tn->bitflags.dummynode == 0)
	    {
	      /* from dummy node to real node */

	      /* check for multiple arrows also at dummy nodes */
	      if ((deptr->de->ue->bitflags.arrows == 1) && (multarrows == 1))
		{
		  if (deptr->de->ue->bitflags.reversed == 1)
		    {
		      /* up arrow */
		    }
		  else
		    {
		      /* down arrow */
		    }
		}
	      /* draw edge lines */

	      /*
	       * cairo_move_to (crp, fnx1, fny2);
	       * cairo_line_to (crp, fnx1, flhny);
	       * cairo_line_to (crp, tnx1, tny0);
	       * cairo_line_to (crp, tnx1, tny1);
	       */

	      /* cairo_move_to (crp, fnx1, fny2); cairo_line_to (crp, fnx1, flhny); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, fny2, fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      fprintf (f, "</dia:object>\n");
	      /* cairo_line_to (crp, fnx1, flhny); cairo_line_to (crp, tnx1, tny0); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, flhny, tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      fprintf (f, "</dia:object>\n");
	      /* cairo_line_to (crp, tnx1, tny0); cairo_line_to (crp, tnx1, tny1); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", tnx1, tny0, tnx1, tny1);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny1);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      /* connect at north of to node */
	      fprintf (f, "<dia:connections>\n");
	      fprintf (f, "<dia:connection handle=\"0\" to=\"O%d\" connection=\"1\"/>\n", deptr->de->ue->tn->objectnr);
	      fprintf (f, "</dia:connections>\n");
	      fprintf (f, "</dia:object>\n");
	      /* draw arrow at to node */
	      if ((deptr->de->ue->bitflags.arrows == 1) && ((deptr->de->ue->bitflags.reversed == 0) || (deptr->de->ue->bitflags.botharrows == 1)))
		{
		  /* draw arrow at to node but not at edge label node */
		  if (deptr->de->ue->tn->bitflags.edgelabel == 0)
		    {
		      if ((tny1 - tny0) < 4)
			{
			}
		      else
			{
			}
		    }
		}
	    }
	  else
	    {
	      /* from dummy node to dummy node */

	      /* check for multiple arrows also at dummy nodes */
	      if ((deptr->de->ue->bitflags.arrows == 1) && (multarrows == 1))
		{
		  if (deptr->de->ue->bitflags.reversed == 1)
		    {
		      /* up arrow */
		    }
		  else
		    {
		      /* down arrow */
		    }
		}
	      /* draw edge lines */

	      /*
	       * cairo_move_to (crp, fnx1, fny2);
	       * cairo_line_to (crp, fnx1, flhny);
	       * cairo_line_to (crp, tnx1, tny0);
	       * cairo_line_to (crp, tnx1, tny1);
	       */

	      /* cairo_move_to (crp, fnx1, fny2); cairo_line_to (crp, fnx1, flhny); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, fny2, fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, fny2);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      fprintf (f, "</dia:object>\n");
	      /* cairo_line_to (crp, fnx1, flhny); cairo_line_to (crp, tnx1, tny0); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", fnx1, flhny, tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", fnx1, flhny);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      fprintf (f, "</dia:object>\n");
	      /* cairo_line_to (crp, tnx1, tny0); cairo_line_to (crp, tnx1, tny1); */
	      fprintf (f, "<dia:object type=\"Standard - Line\" version=\"0\" id=\"O%d\">\n", objectcount);
	      objectcount = objectcount + 1;
	      fprintf (f, "<dia:attribute name=\"obj_pos\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"obj_bb\">\n");
	      /* start end */
	      fprintf (f, "<dia:rectangle val=\"%f,%f;%f,%f\"/>\n", tnx1, tny0, tnx1, tny1);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"conn_endpoints\">\n");
	      /* start */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny0);
	      /* end */
	      fprintf (f, "<dia:point val=\"%f,%f\"/>\n", tnx1, tny1);
	      fprintf (f, "</dia:attribute>\n");
	      fprintf (f, "<dia:attribute name=\"numcp\">\n");
	      fprintf (f, "<dia:int val=\"1\"/>\n");
	      fprintf (f, "</dia:attribute>\n");
	      if (deptr->de->ue->color != 0)
		{
		  red = (deptr->de->ue->color & 0x00ff0000) >> 16;
		  green = (deptr->de->ue->color & 0x0000ff00) >> 8;
		  blue = (deptr->de->ue->color & 0x000000ff);
		  fprintf (f, "<dia:attribute name=\"line_color\">\n");
		  fprintf (f, "<dia:color val=\"#%02x%02x%02x\"/>\n", red, green, blue);
		  fprintf (f, "</dia:attribute>\n");
		}

	      if (deptr->de->ue->bitflags.style)
		{
		  fprintf (f, "<dia:attribute name=\"line_style\">\n");
		  if (deptr->de->ue->bitflags.style == ESTYLE_DASHED)
		    {
		      fprintf (f, "<dia:enum val=\"1\"/>\n");
		    }
		  if (deptr->de->ue->bitflags.style == ESTYLE_DOTTED)
		    {
		      fprintf (f, "<dia:enum val=\"4\"/>\n");
		    }
		  fprintf (f, "</dia:attribute>\n");
		}

	      fprintf (f, "</dia:object>\n");
	      /* check for multiple arrows also at dummy nodes */
	      if ((deptr->de->ue->bitflags.arrows == 1) && (multarrows == 1))
		{
		  if (deptr->de->ue->bitflags.reversed == 1)
		    {
		      /* up arrow */
		    }
		  else
		    {
		      /* down arrow */
		    }
		}
	    }

	  /* next edge in this level */
	  deptr = deptr->next;
	}
      /* next level in drawing */
    }

  /* tail */
  fprintf (f, "</dia:layer>\n");
  fprintf (f, "</dia:diagram>\n");
  /* ready */
  fclose (f);
  free (diafilename);
  diafilename = NULL;
  return;
}

void
on_top_level_window_saveasels1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *elsfilename = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  FILE *f = NULL;
  splay_tree_node spn = (splay_tree_node) 0;
  int nc = 0;
  int ec = 0;
  struct uedge *ue = (struct uedge *) 0;
  char *sfn = NULL;

  if (menuitem)
    {
    }

  if (user_data)
    {
    }

  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As els",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);

  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      elsfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (elsfilename);
  f = fopen (sfn, "wb");
  /* check if open */
  if (f == NULL)
    {
      free (elsfilename);
      elsfilename = NULL;
      return;
    }

  /* count actual nodes+edges in data onscreen */
  nc = 0;

  if (splay_tree_has_data (sp_parsedwnl))
    {
      spn = splay_tree_min (sp_parsedwnl);
      while (spn)
	{
	  nc = nc + 1;
	  spn = splay_tree_successor (sp_parsedwnl, spn->key);
	}
    }

  ec = 0;

  if (splay_tree_has_data (sp_parsedwel))
    {
      spn = splay_tree_min (sp_parsedwel);
      while (spn)
	{
	  ec = ec + 1;
	  spn = splay_tree_successor (sp_parsedwel, spn->key);
	}
    }

  if (nc)
    {

      /* number of nodes, edges, deteled edges */
      fprintf (f, "%d %d %d\n", nc, ec, 0);

      /* write the edge data */
      if (splay_tree_has_data (sp_parsedwel))
	{
	  spn = splay_tree_min (sp_parsedwel);
	  while (spn)
	    {
	      ue = (struct uedge *) spn->value;

	      if (ue->bitflags.reversed)
		{
		  fprintf (f, "%d %d\n", ue->tn->number, ue->fn->number);
		}
	      else
		{
		  fprintf (f, "%d %d\n", ue->fn->number, ue->tn->number);
		}

	      spn = splay_tree_successor (sp_parsedwel, spn->key);
	    }
	}

    }
  else
    {
      /* no node data shouldnothappen */
      fprintf (f, "%d %d %d\n", 0, 0, 0);
    }

  /* ready */
  fclose (f);
  free (elsfilename);
  elsfilename = NULL;

  return;
}

/***zz3***save tulip ***/

/* save as tulip software tlp format */
void
on_top_level_window_saveastulip1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *tulipfilename = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  FILE *fstream = NULL;
  struct drawn *nptr = NULL;
  struct drawe *eptr = NULL;
  int edgecount = 0;
  char *s = NULL;
  char *sfn = NULL;
  if (menuitem)
    {
    }

  if (user_data)
    {
    }

  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As tlp",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);

  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      tulipfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (tulipfilename);
  fstream = fopen (sfn, "wb");
  /* check if open */
  if (fstream == NULL)
    {
      free (tulipfilename);
      tulipfilename = NULL;
      return;
    }

  /* header of tulip data file */
  fprintf (fstream, "(tlp \"2.3\"\n");
  fprintf (fstream, "(date \"31-10-2015\")\n");
  fprintf (fstream, "(author \"%s\")\n", PACKAGE_NAME);
  fprintf (fstream, "(comments \"This file is generated by %s %s\")\n", PACKAGE_STRING, PACKAGE_URL);
  /* list of nodes to draw */
  nptr = drawnl;
  /* nodes in the drawing */
  fprintf (fstream, "%s", "(nodes ");
  while (nptr)
    {
      fprintf (fstream, "%d ", nptr->un->number);
      nptr = nptr->next;
    }
  fprintf (fstream, "%s\n", ")");
  eptr = drawel;
  /* edges in the drawing */
  if (eptr)
    {
      /* edge count *must* start at 0 */
      edgecount = 0;
      while (eptr)
	{
	  fprintf (fstream, "(edge %d %d %d)\n", edgecount, eptr->ue->fn->number, eptr->ue->tn->number);
	  edgecount = edgecount + 1;
	  eptr = eptr->next;
	}

      fprintf (fstream, "%s\n", ")");
    }

  nptr = drawnl;
  /* node and edge colors does not work as expected */
  /* 0 indicates root graph */
  fprintf (fstream, "%s\n", "(property  0 color \"viewColor\"");
  /* default rgba for node and edge */
  fprintf (fstream, "%s\n", "(default \"(255,255,255,255)\" \"(0,0,0,0)\")");
  while (nptr)
    {
      /* seems to need 0 for black edge lines */
      fprintf (fstream, "(node %d \"(%d,%d,%d,255)\")\n", nptr->un->number, 0 /* ((nptr->un->fillcolor & 0x00ff0000) >> 16) */ ,
	       0 /* ((nptr->un->fillcolor & 0x0000ff00) >> 8) */ ,
	       0 /* (nptr->un->fillcolor & 0x000000ff) */ );
      nptr = nptr->next;
    }

  eptr = drawel;
  /* color of the edges in the drawing */
  if (eptr)
    {
      /* edge counter *must* start at 0 */
      edgecount = 0;
      while (eptr)
	{
	  fprintf (fstream, "(edge %d \"(%d,%d,%d,255)\")\n", edgecount,
		   /* 0 */ ((eptr->ue->color & 0x00ff0000) >> 16),
		   /* 0 */ ((eptr->ue->color & 0x0000ff00) >> 8),
		   /* 0 */ (eptr->ue->color & 0x000000ff));
	  edgecount = edgecount + 1;
	  eptr = eptr->next;
	}
    }

  /* end of color info */
  fprintf (fstream, "%s\n", ")");
  nptr = drawnl;
  /* node labels */
  /* 0 indicates root graph */
  fprintf (fstream, "%s\n", "(property  0 string \"viewLabel\"");
  fprintf (fstream, "%s\n", "(default \"\" \"\")");
  while (nptr)
    {
      if (nptr->un->label)
	{
	  fprintf (fstream, "(node %d ", nptr->un->number);
	  s = nptr->un->label;
	  fputc ('"', fstream);
	  while (*s)
	    {
	      if (*s == '\n')
		{
		  fputc ('\\', fstream);
		  fputc ('n', fstream);
		}
	      else if (*s == '"')
		{
		  fputc ('\\', fstream);
		  fputc ('"', fstream);
		}
	      else
		{
		  fputc (*s, fstream);
		}
	      s++;
	    }
	  fputc ('"', fstream);
	  fprintf (fstream, "%s\n", ")");
	}
      else
	{
	  /* no label then no output needed */
	}
      nptr = nptr->next;
    }

  fprintf (fstream, "%s\n", ")");
  /* data can be extended to improve drawing */
  /* ready */
  fclose (fstream);
  /* */
  free (tulipfilename);
  tulipfilename = NULL;
  return;
}


/***zz4***save manual ***/

/* save manual document */
void
on_top_level_window_saveasmanual1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  char *manualfilename = NULL;
  FILE *fstream = NULL;
  unsigned int i = 0;
  char *sfn = NULL;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }

  dialog = gtk_file_chooser_dialog_new ("Save As tuxsee.pdf",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  /* change to last used dir if any */
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  /* ask to override existing image */
  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
  /* get the filename */
  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      manualfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      /* no filename */
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (manualfilename);
  fstream = fopen (sfn, "wb");
  if (fstream == NULL)
    {
      free (manualfilename);
      manualfilename = NULL;
      return;
    }

  for (i = 0; i < n_manual_bytes; i++)
    {
      fputc (manual_bytes[i], fstream);
    }

  fclose (fstream);
  free (manualfilename);
  manualfilename = NULL;
  return;
}

/* save source.tgz */
void
on_top_level_window_saveassource1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  char *sourcefilename = NULL;
  FILE *fstream = NULL;
  unsigned int i = 0;
  char *sfn = NULL;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }

  dialog = gtk_file_chooser_dialog_new ("Save As tuxsee.tgz",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  /* change to last used dir if any */
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  /* ask to override existing image */
  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
  /* get the filename */
  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      sourcefilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      /* no filename */
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (sourcefilename);
  fstream = fopen (sfn, "wb");
  /* check if open */
  if (fstream == NULL)
    {
      free (sourcefilename);
      sourcefilename = NULL;
      return;
    }

  for (i = 0; i < n_source_bytes; i++)
    {
      fputc (source_bytes[i], fstream);
    }

  fclose (fstream);
  free (sourcefilename);
  sourcefilename = NULL;
  return;
}

/***zz5***save svgjs ***/

/*
   * to update with more svg drawing features
   * and more data from the node + edge data.
   *
   * this svg + javascript can be used with firefox
   * internet browser but does not work with inkscape
   * which does not handle the javascript.
   *
   * the order of the js id hierarchy names in the code must be:
   * _1
   * _1_1
   * _1_1_1
   * _1_1_1_1
   * _1_2
   * _1_2_1
   * _1_2_2
   * _1_2_2_1
   * _1_2_2_1_1
   * _1_3
   * _1_3_1
   * etc. and this depends on the out-going edge of a node.
   * the edge at the node in the js is one of the incoming
   * edges to a node with optional path with dummy nodes.
   * when node has multiple incoming edges the the node
   * is multiple times in the draw data with different
   * js identifiers.
   * when a node has no out-going edges the +/- box at the node
   * to click for expand/collapse feature is omitted.
   * the text size of the node is estimated from the font
   * size setting.
 */

/* used svg text font name and pointsize (value 8 is too small text) */
/* #define SVG_FONTNAME "arial" */
/* #define SVG_FONTNAME "serif" */
#define SVG_FONTNAME "monospace"
#define SVG_POINTSIZE 10
/* text size (x,y) factors for char to pixels */
#define SVG_TXF 6
#define SVG_TYF 10
/* text size (x,y) border around text */
#define SVG_TXB 2
#define SVG_TYB 2
/* (x,y) offset of drawing on window */
#define SVG_XOFFSET 5
#define SVG_YOFFSET 25
/* (x,y) spacing in pixels between nodes */
#define SVG_XSPACING 6
#define SVG_YSPACING 16

/* */
static splay_tree svgjs_spnodes = (splay_tree) 0;
static splay_tree svgjs_mt = (splay_tree) 0;
static splay_tree svgjs_splevels = (splay_tree) 0;

/* delete the splay tree value data */
static void
on_top_level_window_saveassvgjs1_activate3_free (splay_tree_value ptr)
{
  if (ptr)
    {
      myfree ((void *) ptr, __FUNCTION__, __LINE__);
    }
  return;
}

/* translate draw data into svg xml */
static void
on_top_level_window_saveassvgjs1_activate5 (FILE * f, struct svgel *psvel)
{
  splay_tree usepoe = (splay_tree) 0;
  struct svgel *ps = NULL;
  struct svgnode *sn = NULL;
  struct unode *un = NULL;
  struct unode *fnode2 = NULL;
  struct unode *tnode2 = NULL;
  char *label = "null";
  char *nname = "null";
  char *p = NULL;
  int i = 0;
  int fnx1 = 0;
  int fny1 = 0;
  int hx1 = 0;
  int hy1 = 0;
  int tnx1 = 0;
  int tny1 = 0;
  int fnnum = 0;
  int tnnum = 0;
  struct uedge *uee = NULL;
  struct uedge *ue = NULL;
  splay_tree_node spn = (splay_tree_node) 0;
  splay_tree_node spn0 = (splay_tree_node) 0;
  struct svgnode *fsnode = NULL;
  struct svgnode *fsnode2 = NULL;
  struct svgnode *tsn = NULL;

#define N1 "<g id='%s' class='box' transform='translate(%d,%d)' visibility='visible'>\n"

#define N2 " <rect class='%s' x='0' y='0' width='%d' height='%d' rx='3' " "onmouseover='makeVisible(\"%s\")' onmouseout='makeHidden(\"%s\")'/>\n"

#define N3T1 " <text class='visible' x='2' y='%d'>"

  char *n3t2 = "</text>";

#define N5T1 " <text class='hidden' visibility='hidden' x='2' y='%d'>"

  char *n5t2 = "</text>";

#define N80 " <line class='connection' x1='%d' y1='%d' x2='%d' y2='%d'/>\n"

#define N98 " <use x='%d' y='%d' xlink:href='#minus' id='s%s' onclick='show(\"%s\")'/>\n"

  char *n99 = "</g>";

  /* okay if nil */
  if (psvel == NULL)
    {
      return;
    }

  /* first edge to draw */
  if (psvel->ue)
    {
      uee = psvel->ue;
    }
  else
    {
      uee = NULL;
    }

  /* it can normally happen there is no uee and that is okay. */
  if (option_gdebug)
    {
      printf ("uee=%p\n", (void *) (psvel->ue));
      fflush (stdout);
    }

  /* */
  if (psvel->sn)
    {
      sn = psvel->sn;
    }
  else
    {
      sn = NULL;
    }

  if (sn != NULL)
    {
      un = sn->un;
      label = un->label;
      if (label == NULL)
	{
	  label = "nil";
	}
      nname = un->name;
      if (nname == NULL)
	{
	  nname = "nil";
	}
    }

  /*
   * The syntax for writing comments in XML is similar to that of HTML.
   * <!-- This is a comment -->
   * Two dashes in the middle of a comment are not allowed.
   * a "--" is in a xml comment not allowed, then nodename must not be --
   */
  if (strcmp (nname, "--") == 0)
    {
      fprintf (f, "<!-- %s -->\n", psvel->id);
    }
  else
    {
      fprintf (f, "<!-- %s node %s -->\n", psvel->id, nname);
    }

  /* print start of node with the (x,y) position in drawing */
  fprintf (f, N1, psvel->id, sn->x0, sn->y1);
  /* draw node shape, to update for more shapes and node parameters */
  if ((sn->bbx != 0) && (sn->bby != 0))
    {
      if (un->bitflags.edgelabel)
	{
	  /* at edgelabel node draw white box, or no box at all */
	  fprintf (f, N2, "edgelabelnode", sn->bbx, sn->bby, psvel->id, psvel->id);
	}
      else
	{
	  /* regular node or subgraph summary node */
	  fprintf (f, N2, "nodenode", sn->bbx, sn->bby, psvel->id, psvel->id);
	}
    }
  else
    {
      /* should not happen then draw a 23x23 tiny box
       * fprintf (f, n2, 23, 23, psvel->id, psvel->id);
       */
      fprintf (f, "<!-- shouldnothappen node %s fixme at %s %d -->\n", un->name, __FUNCTION__, (int) __LINE__);
    }

  i = SVG_POINTSIZE;
  /*
   * There are 5 pre-defined entity references in XML:
   * &lt;        <       less than
   * &gt;        >       greater than
   * &amp;       &       ampersand
   * &apos;      '       apostrophe
   * &quot;      "       quotation mark
   * Only < and & are strictly illegal in XML, but it is a good habit to replace > with &gt; as well.
   */
  fprintf (f, N3T1, i);
  p = label;
  while ((*p))
    {
      if ((*p) == '\n')
	{
	  fprintf (f, "%s\n", n3t2);
	  i = i + SVG_POINTSIZE;
	  fprintf (f, N3T1, i);
	}
      else if ((*p) == '<')
	{
	  fputs ("&lt;", f);
	}
      else if ((*p) == '>')
	{
	  fputs ("&gt;", f);
	}
      else if ((*p) == '&')
	{
	  fputs ("&amp", f);
	}
      else if ((*p) == '\'')
	{
	  fputs ("&apos;", f);
	}
      else if ((*p) == '"')
	{
	  fputs ("&quot;", f);
	}
      else
	{
	  fprintf (f, "%c", (*p));
	}
      p = (p + 1);
    }
  fprintf (f, "%s\n", n3t2);
  /* hidden text shown at mouseover() with the internal node name */
  i = SVG_POINTSIZE;
  fprintf (f, N5T1, i);
  p = nname;
  while ((*p))
    {
      if ((*p) == '\n')
	{
	  fprintf (f, "%s\n", n5t2);
	  i = i + SVG_POINTSIZE;
	  fprintf (f, N5T1, i);
	}
      else if ((*p) == '<')
	{
	  fputs ("&lt;", f);
	}
      else if ((*p) == '>')
	{
	  fputs ("&gt;", f);
	}
      else if ((*p) == '&')
	{
	  fputs ("&amp", f);
	}
      else if ((*p) == '\'')
	{
	  fputs ("&apos;", f);
	}
      else if ((*p) == '"')
	{
	  fputs ("&quot;", f);
	}
      else
	{
	  fprintf (f, "%c", (*p));
	}
      p = (p + 1);
    }
  fprintf (f, "%s\n", n5t2);
  /* hidden text shown at mouseover() with the internal javascript id name */
  i = SVG_POINTSIZE;
  i = i + SVG_POINTSIZE;
  fprintf (f, N5T1, i);
  /* the id name _1_1_2 etc. */
  if (psvel->id)
    {
      p = psvel->id;
    }
  else
    {
      p = "";
    }

  /* */
  while ((*p))
    {
      if ((*p) == '\n')
	{
	  fprintf (f, "%s\n", n5t2);
	  i = i + SVG_POINTSIZE;
	  fprintf (f, N5T1, i);
	}
      else if ((*p) == '<')
	{
	  fputs ("&lt;", f);
	}
      else if ((*p) == '>')
	{
	  fputs ("&gt;", f);
	}
      else if ((*p) == '&')
	{
	  fputs ("&amp", f);
	}
      else if ((*p) == '\'')
	{
	  fputs ("&apos;", f);
	}
      else if ((*p) == '"')
	{
	  fputs ("&quot;", f);
	}
      else
	{
	  fprintf (f, "%c", (*p));
	}
      p = (p + 1);
    }
  fprintf (f, "%s\n", n5t2);
  /* <line ...> edge line statements */
  if (uee != NULL)
    {
      fnnum = uee->fn->number;
      tnnum = uee->tn->number;
      /* get node */
      spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) fnnum);
      if (spn)
	{
	  fsnode2 = (struct svgnode *) spn->value;
	}
      else
	{
	  if (option_gdebug)
	    {
	      printf ("%s(): could not find from-node number %d\n", __FUNCTION__, fnnum);
	      fflush (stdout);
	    }
	  fsnode2 = (struct svgnode *) 0;
	}
      /* get node */
      spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) tnnum);
      if (spn)
	{
	  tsn = (struct svgnode *) spn->value;
	}
      else
	{
	  tsn = (struct svgnode *) 0;
	}
      /* */
      if (fsnode2 && tsn)
	{
	  fprintf (f, " <!-- edge from %s to %s -->\n", fsnode2->un->name, tsn->un->name);
	}
      /* check if to-node is a dummy node */
      if (uee->tn->label == NULL)
	{			/* option to print the follow edges here */
	}
    }

  /* to update draw spline soft bended edges
   * svg has multiple options for this
   * can be done even better with help of javascript
   * edge options in ue are dotted, dashed lines
   * color of edge line and thickness.
   */
  if (uee != NULL)
    {
      fnnum = uee->fn->number;
      tnnum = uee->tn->number;
      if (option_gdebug)
	{
	  printf ("%s(): looking for edge %d to %d\n", __FUNCTION__, fnnum, tnnum);
	  fflush (stdout);
	}
      /* get node */
      spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) fnnum);
      if (spn != (splay_tree_node) 0)
	{
	  fsnode = (struct svgnode *) spn->value;
	}
      else
	{
	  fsnode = NULL;
	}
      /* get node */
      spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) tnnum);
      if (spn != (splay_tree_node) 0)
	{
	  tsn = (struct svgnode *) spn->value;
	}
      else
	{
	  tsn = NULL;
	}
      /* both should be available normally */
      if (fsnode && tsn)
	{
	  fprintf (f, " <!-- edge from %s to %s -->\n", fsnode->un->name, tsn->un->name);
	  fnx1 = fsnode->x1;
	  /* compensate for the +/- box at bottom of node, sized (10x10) px */
	  fny1 = (fsnode->y2 + 5 + 0);
	  tnx1 = tsn->x1;
	  tny1 = tsn->y1;
	  hx1 = ((fnx1 + tnx1) / 2);
	  hy1 = ((fny1 + tny1) / 2);
	  /* correct for offset of node */
	  fnx1 = (fnx1 - sn->x0);
	  fny1 = (fny1 - sn->y1);
	  tnx1 = (tnx1 - sn->x0);
	  tny1 = (tny1 - sn->y1);
	  hx1 = (hx1 - sn->x0);
	  hy1 = (hy1 - sn->y1);
	  fprintf (f, N80, /* start */ fnx1, fny1,
		   /* end-first-level */ fnx1,
		   (fsnode->y3 - sn->y1));
	  /* directly to next level */
	  fprintf (f, N80, /* end-first-level */ fnx1,
		   (fsnode->y3 - sn->y1),	/* begin next-level */
		   tnx1, (tsn->y0 - sn->y1));
	  fprintf (f, N80,	/* begin next-level */
		   tnx1, (tsn->y0 - sn->y1),	/* endpoint */
		   tnx1, tny1);
	  /* direct line
	   * fprintf (f, n80, fnx1, fny1, tnx1, tny1);
	   */
	  /* check if to is a dummy node */
	  if (uee->tn->label == NULL)
	    {
	      fnode2 = uee->fn;
	      tnode2 = uee->tn;

	      if (splay_tree_has_data (uee->tn->sp_poe))
		{
		  usepoe = uee->tn->sp_poe;
		  spn0 = splay_tree_min (usepoe);

		  while (spn0)
		    {
		      ue = (struct uedge *) spn0->value;
		      /* check outgoing edges */
		      if (ue->fn == tnode2)
			{
			  tnode2 = ue->tn;
			  /* check if found a real node */
			  if (tnode2->label)
			    {
			      /* set as real node to node */
			      break;
			    }
			  fnode2 = ue->fn;
			  fprintf (f, " <!-- edge from %s to %s -->\n", fnode2->name, tnode2->name);
			  /* get the data of the line */
			  fnnum = fnode2->number;
			  tnnum = tnode2->number;
			  /* */
			  fsnode = NULL;
			  tsn = NULL;
			  /* get node */
			  spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) fnnum);
			  if (spn)
			    {
			      fsnode = (struct svgnode *) spn->value;
			    }
			  else
			    {
			      fsnode = NULL;
			    }
			  /* get node */
			  spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) tnnum);
			  if (spn)
			    {
			      tsn = (struct svgnode *) spn->value;
			    }
			  else
			    {
			      tsn = NULL;
			    }
			  /* both should be available */
			  if (fsnode && tsn)
			    {
			      /* this is a edge from dummynode to dummy node */
			      fnx1 = fsnode->x1;
			      fny1 = (fsnode->y2 + 0);
			      tnx1 = tsn->x1;
			      tny1 = tsn->y1;
			      hx1 = ((fnx1 + tnx1) / 2);
			      hy1 = ((fny1 + tny1) / 2);
			      /* correct for offset of node */
			      fnx1 = (fnx1 - sn->x0);
			      fny1 = (fny1 - sn->y1);
			      tnx1 = (tnx1 - sn->x0);
			      tny1 = (tny1 - sn->y1);
			      hx1 = (hx1 - sn->x0);
			      hy1 = (hy1 - sn->y1);
			      /* to update this path
			       * direct line
			       * fprintf (f, n80, fnx1, fny1, tnx1, tny1);
			       */
			      fprintf (f, N80, /* start */ fnx1, fny1,
				       /* end-first-level */ fnx1,
				       (fsnode->y3 - sn->y1));
			      /* directly to next level */
			      fprintf (f, N80, /* end-first-level */ fnx1,
				       (fsnode->y3 - sn->y1),	/* begin next-level */
				       tnx1, (tsn->y0 - sn->y1));
			      fprintf (f, N80,	/* begin next-level */
				       tnx1, (tsn->y0 - sn->y1),	/* endpoint */
				       tnx1, tny1);
			    }
			  /* end of edge line */
			  /* follow to next edge */
			  fnode2 = tnode2;
			  if (splay_tree_has_data (tnode2->sp_poe))
			    {
			      usepoe = tnode2->sp_poe;
			      spn0 = splay_tree_min (tnode2->sp_poe);
			      continue;
			    }
			  else
			    {
			      break;
			    }
			}

		      splay_tree_successor (usepoe, spn0->key);
		    }
		}


	      /* it can happen last edge is missing. to update. */
	      if (ue == NULL)
		{
		  printf ("%s(): at line %d nil poeptr is unexpected\n", __FUNCTION__, (int) __LINE__);
		  fflush (stdout);
		}

	      /* */
	      if (ue)
		{
		  fnode2 = ue->fn;
		  /* last edge from dummynode to real node */
		  fprintf (f, " <!-- edge from %s to %s -->\n", fnode2->name, tnode2->name);
		  /* */
		  /* get the data of the line */
		  fnnum = fnode2->number;
		  tnnum = tnode2->number;
		  /* */
		  fsnode = NULL;
		  tsn = NULL;
		  /* get node */
		  spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) fnnum);
		  if (spn)
		    {
		      fsnode = (struct svgnode *) spn->value;
		    }
		  else
		    {
		      fsnode = NULL;
		    }
		  /* get node */
		  spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) tnnum);
		  if (spn)
		    {
		      tsn = (struct svgnode *) spn->value;
		    }
		  else
		    {
		      tsn = NULL;
		    }
		  /* both should be available */
		  if (fsnode && tsn)
		    {
		      /* this is a edge from dummynode to dummy node */
		      fnx1 = fsnode->x1;
		      fny1 = (fsnode->y2 + 0);
		      tnx1 = tsn->x1;
		      tny1 = tsn->y1;
		      hx1 = ((fnx1 + tnx1) / 2);
		      hy1 = ((fny1 + tny1) / 2);
		      /* correct for offset of node */
		      fnx1 = (fnx1 - sn->x0);
		      fny1 = (fny1 - sn->y1);
		      tnx1 = (tnx1 - sn->x0);
		      tny1 = (tny1 - sn->y1);
		      hx1 = (hx1 - sn->x0);
		      hy1 = (hy1 - sn->y1);
		      /* to update this path
		       * direct line
		       * fprintf (f, n80, fnx1, fny1, tnx1, tny1);
		       */
		      fprintf (f, N80, /* start */ fnx1, fny1, /* end-first-level */ fnx1, (fsnode->y3 - sn->y1));
		      /* directly to next level */
		      fprintf (f, N80, /* end-first-level */ fnx1, (fsnode->y3 - sn->y1), /* begin next-level */ tnx1, (tsn->y0 - sn->y1));
		      fprintf (f, N80, /* begin next-level */ tnx1, (tsn->y0 - sn->y1), /* endpoint */ tnx1, tny1);
		    }
		  /* if(poeptr)... */
		}
	    }
	  /* if(uee->tn->label==NULL)... */
	}
      /* if(fsnode && tsn)... */
    }

  /* optional <use ...> with clickable +/- box (10x10) px. and no data if there is no outgoing edge. */
  if (sn->outdegree != 0)
    {
      /* set the clickable +/- at middle of node, click box is 10 px, then -5 px to add. */
      fprintf (f, N98, ((sn->bbx / 2) - 5), (sn->bby - 0), psvel->id, psvel->id);
    }

  /* last is </g> */
  fprintf (f, "%s\n", n99);
  ps = psvel->svel;
  while (ps)
    {
      on_top_level_window_saveassvgjs1_activate5 (f, ps);
      ps = ps->next;
    }

  return;
}

/* build draw data */
static void
on_top_level_window_saveassvgjs1_activate4 (struct svgel *ps)
{
  struct svgnode *sn = NULL;
  struct svgnode *sn2 = NULL;
  struct unode *un = NULL;
  struct unode *un2 = NULL;
  struct svgel *psvel = NULL;
  struct unode *tnode = NULL;
  struct unode *tnode2 = NULL;
  struct unode *rtnode = NULL;
  struct uedge *ue = (struct uedge *) 0;
  struct uedge *ue2 = (struct uedge *) 0;
  struct uedge *ue3 = (struct uedge *) 0;
  int j = 0;
  int nc = 0;
  char *elbuf = NULL;
  splay_tree_node spn = (splay_tree_node) 0;
  splay_tree_node spn0 = (splay_tree_node) 0;
  splay_tree_node spn1 = (splay_tree_node) 0;
  splay_tree_node spn2 = (splay_tree_node) 0;
  splay_tree usepoe = (splay_tree) 0;
  splay_tree usepoe2 = (splay_tree) 0;

  if (ps == NULL)
    {
      return;
    }

  /* node svg data */
  sn = ps->sn;
  /* node data */
  un = sn->un;

  if (option_gdebug)
    {
      printf ("%s(): at %s with node %s\n", __FUNCTION__, ps->id, un->name);
      fflush (stdout);
    }

  if (un->label == NULL)
    {
      /* skip dummy nodes */
      return;
    }

  /* counter for subs */
  j = 1;

  /* get part-of-edge list */
  if (splay_tree_has_data (un->sp_poe))
    {

      spn0 = splay_tree_min (un->sp_poe);

      /* scan for outgoing edges */
      while (spn0)
	{
	  ue = (struct uedge *) spn0->value;

	  /* check outgoing edges */
	  if (ue->fn == un)
	    {

	      /* set to and real to node */
	      tnode = ue->tn;
	      rtnode = ue->tn;
	      /* check for dummy node */
	      if (ue->tn->label == NULL)
		{
		  /* to node is a dummy node, follow for a real node */
		  tnode2 = ue->tn;

		  if (splay_tree_has_data (tnode2->sp_poe))
		    {
		      usepoe = tnode2->sp_poe;
		      spn1 = splay_tree_min (usepoe);

		      while (spn1)
			{
			  ue2 = (struct uedge *) spn1->value;

			  /* check outgoing edges */
			  if (ue2->fn == tnode2)
			    {
			      tnode2 = ue2->tn;
			      /* check if found a real node */
			      if (tnode2->label)
				{
				  /* set as real node to node */
				  rtnode = tnode2;
				  break;
				}
			      if (splay_tree_has_data (tnode2->sp_poe))
				{
				  usepoe = tnode2->sp_poe;
				  spn1 = splay_tree_min (usepoe);
				  continue;
				}
			      else
				{
				  break;
				}
			    }
			  spn1 = splay_tree_successor (usepoe, spn1->key);
			}
		    }

		}

	      if (rtnode != tnode)
		{
		  /* */
		  if (option_gdebug)
		    {
		      printf ("%s(): changed target node\n", __FUNCTION__);
		      fflush (stdout);
		    }
		}
	      /* get node */
	      spn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) rtnode->number);
	      /* */
	      if (spn)
		{
		  /* get the node data */
		  sn2 = (struct svgnode *) spn->value;
		  /* new data to pass on */
		  psvel = mymalloc (sizeof (struct svgel), __FUNCTION__, __LINE__);
		  /* register this malloc */
		  splay_tree_insert (svgjs_mt, (splay_tree_key) psvel, (splay_tree_value) sizeof (struct svgel));
		  /* set rooted on rootgraph */
		  psvel->rootedon = (struct svgel *) ps;
		  /* create id name to use */
		  nc = (int) strlen (ps->id);
		  nc = (nc + 8);
		  elbuf = mymalloc ((size_t) nc, __FUNCTION__, __LINE__);
		  memset (elbuf, 0, (size_t) nc);
		  snprintf (elbuf, (nc - 1), "%s_%d", ps->id, j);
		  psvel->id = uniqstring ((char *) elbuf);
		  myfree ((void *) elbuf, __FUNCTION__, __LINE__);
		  elbuf = NULL;
		  /* */
		  sn2->un = rtnode;
		  if (sn2->un->label == NULL)
		    {
		      /* is a dummy node */
		      un2 = sn2->un;

		      if (splay_tree_has_data (un2->sp_poe))
			{
			  usepoe2 = un2->sp_poe;
			  spn2 = splay_tree_min (usepoe);

			  while (spn2)
			    {
			      ue3 = (struct uedge *) spn2->value;

			      /* check outgoing edges */
			      if (ue3->fn == un2)
				{
				  un2 = ue3->tn;
				  /* check if found a real node */
				  if (un2->label)
				    {
				      break;
				    }

				  /* */
				  if (splay_tree_has_data (un2->sp_poe))
				    {
				      usepoe = un2->sp_poe;
				      spn2 = splay_tree_min (usepoe);
				      continue;
				    }
				  else
				    {
				      break;
				    }

				}

			      spn2 = splay_tree_successor (usepoe2, spn2->key);
			    }
			}

		      /* */
		      if (option_gdebug)
			{
			  printf ("%s(): found %s \"%s\" as real node after dummy node %s\n", __FUNCTION__, un2->name, un2->label, sn2->un->name);
			}
		    }

		  /* set node info */
		  psvel->sn = sn2;
		  /* set edge info */
		  psvel->ue = ue3;
		  /* init empty linkage */
		  psvel->svel = (struct svgel *) 0;
		  psvel->svel_end = (struct svgel *) 0;
		  /* add in linkage */
		  if (ps->svel_end == NULL)
		    {
		      /* first entry */
		      ps->svel = psvel;
		      ps->svel_end = psvel;
		    }
		  else
		    {
		      /* chain on */
		      ps->svel_end->next = psvel;
		      ps->svel_end = psvel;
		    }
		  /* */
		  on_top_level_window_saveassvgjs1_activate4 (psvel);
		  /* next sub */
		  j = (j + 1);
		}
	      else
		{
		  printf ("%s(): shouldnothappen\n", __FUNCTION__);
		}
	    }

	  /* */
	  spn0 = splay_tree_successor (un->sp_poe, spn0->key);
	}
    }

  return;
}

/* add the node+edge data in the body of the svg data */
static void
on_top_level_window_saveassvgjs1_activate3 (FILE * f)
{
  struct uedge *ue0 = (struct uedge *) 0;
  splay_tree_node spn = NULL;
  splay_tree_node spn0 = NULL;
  splay_tree_node spnl = NULL;
  splay_tree_node spnn = NULL;
  splay_tree usepoe = (splay_tree) 0;
  struct svglev *svl = NULL;
  struct svgnode *svn = NULL;
  struct ddn *ddnp = NULL;
  int i = 0;
  int j = 0;
  int k = 0;
  int k2 = 0;
  char c = 0;
  char *p = NULL;
  int w = 0;
  int np = 0;
  int xsum = 0;
  int nx0 = 0;
  int nx1 = 0;
  int maxw = 0;
  int maxly = 0;
  int h = 0;
  int delta = 0;
  struct svgel *psvel = NULL;
  struct svgel *svel = NULL;
  struct svgel *svel_end = NULL;
  char elbuf[8];
  int svg_max_y_pos = 0;
  int svg_max_x_pos = 0;
  char *head0 = "<?xml version='1.0' encoding='UTF-8'?>";
  char *head1 = "<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>";
  /* the page height and width is updated by the javascript in expandAll() */

#define HEAD2 "<svg id='svg' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' onload='loadSVG();' width='%d' height='%d'>\n"

  char *head3 = "<title>tuxsee</title>";
  char *head4 = "<script type='text/ecmascript'><![CDATA[";
  char *head5 =
    "var this_javascript_source_is_gnu_gpl_version_3_free_software = 'https://www.gnu.org/licenses/gpl-3.0.en.html';\n"
    "var dl = 0;\n" "var efBoxes = [];\n" "var eSvg = null;\n" "function loadSVG() {\n"
    "     if (dl) { console.log ('loadsvg()'); }\n"
    "     efBoxes = getElementsByClassName('box', document.getElementsByTagName('g'));\n"
    "     eSvg = document.getElementById('svg');\n" "     expandAll();\n" "}\n"
    "function getElementsByClassName(sClass, nlNodes) {\n" "     var elements = [];\n"
    "     for (var i = 0; i < nlNodes.length; i++) {\n"
    "         if (nlNodes.item(i).nodeType == 1 && sClass == nlNodes.item(i).getAttribute('class')) {\n"
    "             elements.push(nlNodes.item(i));\n" "         }\n" "     }\n" "     return elements;\n" "}\n"
    "function show(sId) {\n" "     var useElement = document.getElementById('s' + sId);\n" "     var moveNext = false;\n"
    "     var eBoxLast;\n" "     var max_x_pos = 500;\n" "     if (notPlus(useElement)) {\n"
    "         eBoxLast = document.getElementById(sId);\n" "         setPlus(useElement);\n"
    "         for (var i = 0; i < efBoxes.length; i++) {\n" "             var eBox = efBoxes[i];\n"
    "             if (moveNext) {\n" "                 move(eBoxLast, eBox);\n"
    "             } else if (isDescendant(sId, eBox.id)) {\n" "                 eBox.setAttribute('visibility', 'hidden');\n"
    "             } else if (isHigherBranch(sId, eBox.id)) {\n" "                 move(eBoxLast, eBox);\n"
    "                 moveNext = true;\n" "             } else { }\n"
    "             if (eBox.getAttribute('visibility') != 'hidden') {\n" "                 eBoxLast = eBox;\n"
    "                 x = xTrans(eBox);\n" "                 if (x > max_x_pos) {\n" "                     max_x_pos = x;\n"
    "                 }\n" "             }\n" "         }\n" "     } else {\n" "         setMinus(useElement);\n"
    "         var skipDescendantsOf;\n" "         for (var i = 0; i < efBoxes.length; i++) {\n"
    "             var eBox = efBoxes[i];\n" "             if (moveNext) {\n" "                 move(eBoxLast, eBox);\n"
    "             } else if (isDescendant(sId, eBox.id) && (!skipDescendantsOf || !isDescendant(skipDescendantsOf.id, eBox.id))) {\n"
    "                 eBox.setAttribute('visibility', 'visible');\n" "                 move(eBoxLast, eBox);\n"
    "                 if (nextClosed(eBox)) {\n" "                     skipDescendantsOf = eBox;\n" "                 }\n"
    "             } else if (isHigherBranch(sId, eBox.id)) {\n" "                 move(eBoxLast, eBox);\n"
    "                 moveNext = true;\n" "             } else {}\n"
    "             if (eBox.getAttribute('visibility') != 'hidden') {\n" "                 eBoxLast = eBox;\n"
    "                 x = xTrans(eBox);\n" "                 if (x > max_x_pos) {\n" "                     max_x_pos = x;\n"
    "                 }\n" "             }\n" "         }\n" "     }\n" "     // setHeight(yTrans(eBoxLast) + 71);\n";

  char *head55 =
    "     // setWidth(max_x_pos + 300);\n" "}\n" "function collapseAll() {\n" "     for (var i = 0; i < efBoxes.length; i++) {\n"
    "         var eBox = efBoxes[i];\n" "         var useElement = document.getElementById('s' + eBox.id);\n"
    "         if (useElement) {\n" "             setPlus(useElement);\n" "         }\n" "         if (eBox.id != '_1') {\n"
    "             eBox.setAttribute('visibility', 'hidden');\n" "         }\n" "     }\n" "     // setHeight(400);\n"
    "     // setWidth(500);\n" "}\n" "function expandAll() {\n" "     var eBoxLast;\n" "     var max_x_pos = 0;\n"
    "     for (var i = 0; i < efBoxes.length; i++) {\n" "         var eBox = efBoxes[i];\n"
    "         var useElement = document.getElementById('s' + eBox.id);\n" "         if (useElement) {\n"
    "             setMinus(useElement);\n" "         }\n" "         move(eBoxLast, eBox);\n"
    "         eBox.setAttribute('visibility', 'visible');\n" "         eBoxLast = eBox;\n" "         var x = xTrans(eBox);\n"
    "         if (x > max_x_pos) {\n" "             max_x_pos = x;\n" "         }\n" "     }\n"
    "     // setHeight(yTrans(eBoxLast) + 71);\n" "     // setWidth(max_x_pos + 300);\n" "}\n" "function makeVisible(sId) {\n"
    "     var childNodes = document.getElementById(sId).childNodes;\n"
    "     var hidden = getElementsByClassName('hidden', childNodes);\n"
    "     var visible = getElementsByClassName('visible', childNodes);\n" "     inheritVisibility(hidden);\n"
    "     hiddenVisibility(visible);\n" "}\n" "function makeHidden(sId) {\n"
    "     var childNodes = document.getElementById(sId).childNodes;\n"
    "     var hidden = getElementsByClassName('hidden', childNodes);\n"
    "     var visible = getElementsByClassName('visible', childNodes);\n" "     inheritVisibility(visible);\n"
    "     hiddenVisibility(hidden);\n" "}\n" "function inheritVisibility(efElements) {\n"
    "     for (var i = 0; i < efElements.length; i++) {\n" "         efElements[i].setAttribute('visibility', 'inherit');\n"
    "     }\n" "}\n" "function hiddenVisibility(efElements) {\n" "     for (var i = 0; i < efElements.length; i++) {\n"
    "         efElements[i].setAttribute('visibility', 'hidden');\n" "     }\n" "}\n" "function nextClosed(eBox) {\n"
    "     var useElement = document.getElementById('s' + eBox.id);\n" "     return (useElement && !notPlus(useElement));\n" "}\n";

  char *head56 =
    "function isHigherBranch(sSerialLower, sSerialHigher) {\n" "     var sLower = sSerialLower.split('_');\n"
    "     var sHigher = sSerialHigher.split('_');\n" "     for (var i = 0; i < sLower.length; i++) {\n"
    "         if (Number(sHigher[i]) > Number(sLower[i])) {\n" "             return true;\n"
    "         } else if (Number(sHigher[i]) < Number(sLower[i])) {\n" "             return false;\n" "         } else {}\n"
    "     }\n" "     return false;\n" "}\n" "function isOnHigherLevel(eBoxLower, eBoxHigher) {\n"
    "     var sLower = eBoxLower.id.split('_');\n" "     var sHigher = eBoxHigher.id.split('_');\n"
    "     for (var i = 0; i < sLower.length; i++) {\n" "         if (Number(sHigher[i]) > Number(sLower[i])) {\n"
    "             return true;\n" "         }\n" "     }\n" "     return false;\n" "}\n"
    "function isDescendant(sSerialAsc, sSerialDesc) {\n"
    "     return (sSerialDesc.length > sSerialAsc.length && sSerialDesc.indexOf(sSerialAsc) === 0);\n" "}\n"
    "function getParent(eBox) {\n" "     var serial = eBox.id.substring(0, eBox.id.lastIndexOf('_'));\n"
    "     return document.getElementById(serial);\n" "}\n" "function move(eBoxLast, eBox) {\n" "     if (!eBoxLast) {\n"
    "         return;\n" "     }\n" "     // if (isOnHigherLevel(eBoxLast, eBox)) {\n"
    "     //     setYTrans(eBox, yTrans(eBoxLast) + 71);\n" "     //     var parent = getParent(eBox);\n"
    "     //     var line = document.getElementById('p' + eBox.id);\n" "     //     if (!parent || !line) {\n"
    "     //         return;\n" "     //     }\n"
    "     //     line.setAttribute('y1', String(yTrans(parent) - yTrans(eBox) + 23));\n" "     // } else {\n"
    "     //     setYTrans(eBox, yTrans(eBoxLast));\n" "     // }\n" "}\n" "function notPlus(eUseElement) {\n"
    "     return (eUseElement.getAttributeNS('http://www.w3.org/1999/xlink', 'href') != '#plus');\n" "}\n"
    "function setPlus(eUseElement) {\n" "     eUseElement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#plus');\n"
    "}\n" "function setMinus(eUseElement) {\n"
    "     eUseElement.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#minus');\n" "}\n" "function setHeight(nHeight) {\n"
    "     eSvg.setAttribute('height', nHeight);\n" "}\n" "function setWidth(nWidth) {\n"
    "     eSvg.setAttribute('width', nWidth);\n" "}\n" "function xTrans(eBox) {\n"
    "     var transform = eBox.getAttribute('transform');\n"
    "     var x = Number(transform.substring(10, Number(transform.length) - 1).split(',')[0]);\n" "     if (!x) {\n"
    "         x = 0;\n" "     }\n" "     return x;\n" "}\n" "function yTrans(eBox) {\n"
    "     var transform = eBox.getAttribute('transform');\n"
    "     var y = Number(transform.substring(10, Number(transform.length) - 1).split(',')[1]);\n" "     if (!y) {\n"
    "         y = 0;\n" "     }\n" "     return y;\n" "}\n" "function setYTrans(eBox, nValue) {\n"
    "     eBox.setAttribute('transform', 'translate(' + xTrans(eBox) + ',' + nValue + ')');\n" "}";
  char *head6 = "]]></script>";
  char *head7 = "<defs>";
  char *head8 = "<style type='text/css'><![CDATA[";

#define HEAD9    "svg {pointer-events: none;}\n" "text {font-family: %s; font-size: %dpx;}\n" \
    "line, polyline, polygon {fill: none; stroke: black;}\n" ".strong {font-size: 12px; font-weight: bold;}\n" \
    ".small {font-size: 5px;}\n" ".big {font-size: 15px; fill: #882222;}\n" \
    ".button {fill: white; stroke: black; pointer-events: all;}\n" ".shadow {fill: #ccccd8; stroke: none;}\n" \
    ".connection {fill: none; stroke: #666666;}\n" ".empty {fill: none; stroke: black;}\n" \
    ".filled {fill: black; stroke: none;}\n" ".nodenode {fill: #FFFFBB; stroke: #776633; pointer-events: all;}\n" \
    ".edgelabelnode {fill: #FFFFFF; stroke: #000000; pointer-events: all;}\n" \
    ".boxelement, .boxany, .boxattribute1, .boxanyattribute {fill: #FFFFBB; stroke: #776633; pointer-events: all;}\n" \
    ".boxattribute2 {fill: #FFFFBB; stroke: #776633; pointer-events: all; stroke-dasharray: 2;}\n" \
    ".boxschema, .boxloop, .boxcompositor {fill: #E7EBF3; stroke: #666677;}\n" \
    ".boxselector, .boxfield, .boxidc {fill: #E0F7B7; stroke: #667733;}\n" ".lax {fill: white; stroke: black;}\n" \
    ".skip {fill: #cc6666; stroke: black;}\n" ".strict {fill: black; stroke: none;}\n" ".border {fill: #f9f9f9; stroke: #dddddd;}\n"

  char *head10 = "]]></style>";
  /* this is the +/- button at bottom of node with size (10,10) px */
  char *head11 =
    "<symbol class='button' id='plus'>\n"
    " <rect x='1' y='1' width='10' height='10'/>\n"
    " <line x1='3' y1='6' x2='9' y2='6'/>\n" " <line x1='6' y1='3' x2='6' y2='9'/>\n" "</symbol>\n"
    "<symbol class='button' id='minus'>\n" " <rect x='1' y='1' width='10' height='10'/>\n" " <line x1='3' y1='6' x2='9' y2='6'/>\n" "</symbol>";
  char *head12 = "</defs>";
  /* this is the box with + and - to expand or collapse all at once */
  char *head13 =
    "<rect class='button' x='300' y='0' width='20' height='20' onclick='collapseAll()'/>\n"
    "<line x1='303' y1='10' x2='317' y2='10'/>\n" "<text x='330' y='20'>collapse</text>";
  char *head14 =
    "<rect class='button' x='400' y='0' width='20' height='20' onclick='expandAll()'/>\n"
    "<line x1='403' y1='10' x2='417' y2='10'/>\n" "<line x1='410' y1='3' x2='410' y2='17'/>\n" "<text x='430' y='20'>expand</text>";
  /* this is the first node with name graph */
  char *head15 =
    "<g id='_1' class='box' transform='translate(100,1)'>\n"
    "<rect class='boxschema' x='0' y='0' width='40' height='20'/>\n" "<text x='4' y='10'>graph</text>\n"
    "<use x='20' y='18' xlink:href='#minus' id='s_1' onclick='show(\"_1\")'/>\n" "</g>";
  /* possible sample output
   * <g id='_1_1' class='box' transform='translate(128,50)'>
   * <rect class='shadow' x='3' y='3' width='237' height='46'/>
   * <rect class='boxelement' x='0' y='0' width='237' height='46'
   * onmouseover='makeVisible("_1_1")' onmouseout='makeHidden("_1_1")'/>
   * <text class='visible' x='5' y='13'>http://www.gnu.org/</text>
   * <text class='hidden' visibility='hidden' x='5' y='13'>nillable: 0</text>
   * <text class='hidden' visibility='hidden' x='5' y='41'>abstract: 0</text>
   * <text class='strong' x='5' y='27'>edge</text>
   * <text class='visible' x='5' y='41'>type: edge.type</text>
   * <line class='connection' x1='-35' y1='23' x2='0' y2='23'/>
   * <use x='236' y='17' xlink:href='#minus' id='s_1_1' onclick='show("_1_1")'/>
   * </g>
   */
  /* build the splay tree data with recalculated node, edge and level information */
  svgjs_spnodes = splay_tree_new (splay_tree_compare_ints, /* free_key() */ NULL,
				  /* free_value() */
				  on_top_level_window_saveassvgjs1_activate3_free);
  svgjs_splevels = splay_tree_new (splay_tree_compare_ints, /* free_key() */ NULL,
				   /* free_value() */
				   on_top_level_window_saveassvgjs1_activate3_free);
  /* create levels data */
  /* k2 is total number of nodes added in svgjs_spnodes splay tree */
  k2 = 0;
  /* scan all levels */
  for (i = 0; i < dli_nlevels; i++)
    {
      svl = mymalloc (sizeof (struct svglev), __FILE__, __LINE__);
      /* set number of nodes+edges in level */
      svl->nnodes = dlip[i]->nnodes;
      svl->nrnodes = 0;
      svl->nelnodes = 0;
      svl->ndnodes = 0;
      svl->nedges = dlip[i]->nedges;
      /* nested splay tree inside splay tree indexed on nodes ordering and node numbers as value */
      svl->spnlist = splay_tree_new (splay_tree_compare_ints, NULL, NULL);
      /* add struct with level-info-data for this level */
      splay_tree_insert (svgjs_splevels, (splay_tree_key) i, (splay_tree_value) svl);
      /* scan list of nodes+dummy-nodes+edgelabel-nodes in this level and count in j */
      j = 0;
      /* k is total number of nodes added in svgjs_spnodes splay tree at this level */
      k = 0;
      /* list of all nodes in this level: dummy+real+edgelabel nodes */
      ddnp = dlip[i]->nl;
      while (ddnp)
	{
	  /* check */
	  if (ddnp->dn->un->pos != j)
	    {
	      printf ("%s(): node %d should have position %d but has position %d\n", __FUNCTION__, ddnp->dn->un->number, j, ddnp->dn->un->pos);
	      fflush (stdout);
	    }
	  /* add to list of nodes in this level, indexed on position and value uniq node number */
	  splay_tree_insert (svl->spnlist, (splay_tree_key) ddnp->dn->un->pos, (splay_tree_value) ddnp->dn->un->number);
	  j = (j + 1);
	  /* check for node types as dummy-node, edgelabel or real node */
	  if (ddnp->dn->un->bitflags.dummynode)
	    {
	      /* dummy node has no label and size (0,0) */
	      svl->ndnodes = (svl->ndnodes + 1);
	    }
	  else if (ddnp->dn->un->bitflags.edgelabel)
	    {
	      /* edge-label has no shape outline */
	      svl->nelnodes = (svl->nelnodes + 1);
	    }
	  else
	    {
	      /* real node or subgraph summary node */
	      svl->nrnodes = (svl->nrnodes + 1);
	    }
	  /* add real, dummy and summary and edgelabels nodes in svgjs_spnodes splay tree indexed on uniq node number */
	  if ((ddnp->dn->un->bitflags.edgelabel) || (ddnp->dn->un->label) || (ddnp->dn->un->bitflags.dummynode))
	    {
	      svn = mymalloc (sizeof (struct svgnode), __FUNCTION__, __LINE__);
	      svn->un = ddnp->dn->un;
	      splay_tree_insert (svgjs_spnodes, (splay_tree_key) ddnp->dn->un->number, (splay_tree_value) svn);
	      k = (k + 1);
	    }
	  /* next node in nodes-list at this level */
	  ddnp = ddnp->next;
	}
      /* update total number of nodes added in svgjs_spnodes splay tree so far */
      k2 = (k2 + k);
      /* do few checks on the nodes in level data */
      if (svl->nnodes == 0)
	{
	  printf ("%s(): nnodes is zero at level %d\n", __FUNCTION__, i);
	  fflush (stdout);
	}
      if ((svl->ndnodes + svl->nrnodes + svl->nelnodes) != svl->nnodes)
	{
	  printf ("%s(): nnodes is %d and that is not same as counted %d\n", __FUNCTION__, svl->nnodes, (svl->ndnodes + svl->nrnodes + svl->nelnodes));
	  fflush (stdout);
	}
      /* */
      if (option_gdebug)
	{
	  printf
	    ("%s(): level %d has %d nodes (%d real-nodes, %d edgelabels, %d dummynodes) added %d nodes in spnodes, total is %d now\n",
	     __FUNCTION__, i, svl->nnodes, svl->nrnodes, svl->nelnodes, svl->ndnodes, k, k2);
	  fflush (stdout);
	}
      /* to next level in for() */
    }

  /* scan the nodes in the splay list and calc the label (x,y) size in chars */
  spn = splay_tree_min (svgjs_spnodes);

  while (spn)
    {
      svn = (struct svgnode *) spn->value;
      /* */
      if (svn)
	{
	  /* select regular nodes and edge label nodes */
	  if (svn->un->label)
	    {
	      svn->nxchars = 0;
	      svn->nychars = 1;
	      k = 0;
	      p = svn->un->label;
	      c = (*p);
	      while (c)
		{
		  /* at newline incr. number of y lines */
		  if (c == '\n')
		    {
		      svn->nychars = (svn->nychars + 1);
		      k = 0;
		    }
		  else
		    {
		      if (k > svn->nxchars)
			{
			  svn->nxchars = k;
			}
		      k = (k + 1);
		    }
		  p = (p + 1);
		  c = (*p);
		}
	      if (option_gdebug)
		{
		  printf ("%s(): label:\n\"%s\" has size (%d,%d)\n", __FUNCTION__, svn->un->label, svn->nxchars, svn->nychars);
		  fflush (stdout);
		}
	      /* update: different node shapes and font sizes need different calculations */
	      /* roughly calc text (x,y) size in pixels */
	      svn->tx = (SVG_TXF * svn->nxchars);
	      svn->ty = (SVG_TYF * svn->nychars);
	      /* add border (x,y) in pixels */
	      svn->bbx = svn->tx + (2 * SVG_TXB);
	      svn->bby = svn->ty + (2 * SVG_TYB);
	    }
	  else
	    {
	      /* this is a dummy node */
	      svn->tx = 0;
	      svn->ty = 0;
	      svn->bbx = 0;
	      svn->bby = 0;
	    }
	}
      spn = splay_tree_successor (svgjs_spnodes, spn->key);
    }

  /* update here for more x pos. algo's */
  maxw = 0;
  /* scan the levels for node x follow-o positioning */
  for (i = 0; i < dli_nlevels; i++)
    {
      spnl = splay_tree_lookup (svgjs_splevels, (splay_tree_key) i);
      svl = (struct svglev *) spnl->value;
      /* */
      if (svl)
	{
	  /* layer starts at x pos 0 */
	  svl->x0 = 0;
	  /* drawing starts at x offset */
	  w = SVG_XOFFSET;
	  /* list of all nodes in this level: dummy+real+edgelabel nodes, indexed on position */
	  if (splay_tree_has_data (svl->spnlist))
	    {
	      /* scan the nodes in this level */
	      spn = splay_tree_min (svl->spnlist);
	      /* foreach() on the splay spnlist */
	      while (spn)
		{
		  /* uniq node number is in spn->value */
		  spnn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) spn->value);
		  /* get node data */
		  svn = (struct svgnode *) spnn->value;
		  /* get node is part-of-edge data */
		  usepoe = svn->un->sp_poe;
		  /* check if node has connections */
		  if (splay_tree_has_data (usepoe) == 0)
		    {
		      /* set start point of node */
		      svn->x0 = w;
		      /* set middle up point of node */
		      svn->x1 = (svn->x0 + (svn->bbx / 2));
		      /* add x size of node */
		      w = (w + svn->bbx);
		      /* add spacing between nodes */
		      w = (w + SVG_XSPACING);
		    }
		  else
		    {
		      np = 0;
		      xsum = 0;
		      nx0 = 0;
		      nx1 = 0;
		      /* scan edges connected to this node */
		      spn0 = splay_tree_min (usepoe);
		      while (spn0)
			{
			  ue0 = (struct uedge *) spn0->value;
			  /* check incoming edges */
			  if (ue0->tn == svn->un)
			    {
			      /* count number of edges */
			      np = (np + 1);
			      /* add the from-node connection pos. */
			      xsum = (xsum + ue0->fn->x1);
			    }
			  splay_tree_successor (usepoe, spn0->key);
			}
		      /* check */
		      if (np == 0)
			{
			  /* no incoming edges to node, add to current pos. */
			  /* set start point of node */
			  svn->x0 = w;
			  /* set middle up point of node */
			  svn->x1 = (svn->x0 + (svn->bbx / 2));
			  /* add x size of node */
			  w = (w + svn->bbx);
			  /* add spacing between nodes */
			  w = (w + SVG_XSPACING);
			}
		      else
			{
			  /* avarage of incoming edges from position */
			  nx1 = (xsum / np);
			  nx0 = (nx1 - svn->bbx);
			  /* check if at a free pos. */
			  if (nx0 >= w)
			    {
			      /* move w to new pos. */
			      w = nx0;
			    }
			  /* set start point of node */
			  svn->x0 = w;
			  /* set middle up point of node */
			  svn->x1 = (svn->x0 + (svn->bbx / 2));
			  /* add x size of node */
			  w = (w + svn->bbx);
			  /* add spacing between nodes */
			  w = (w + SVG_XSPACING);
			}
		    }
		  /* to next node in this level */
		  spn = splay_tree_successor (svl->spnlist, spn->key);
		}
	      /* save width xsize of this level with its offset */
	      svl->wn = (w + SVG_XSPACING);
	      /* */
	      if (option_gdebug)
		{
		  printf ("%s(): level %d has xsize %d pixels, widest level has %d pixels\n", __FUNCTION__, i, w, maxw);
		  fflush (stdout);
		}
	    }
	  else
	    {
	      if (option_gdebug)
		{
		  printf ("%s(): level %d has no nodes, widest level has %d pixels\n", __FUNCTION__, i, maxw);
		  fflush (stdout);
		}
	      /* save width xsize of this level with its offset */
	      svl->wn = (w + SVG_XSPACING);
	    }
	  /* check xsize of widest level */
	  if (svl->wn > maxw)
	    {
	      maxw = svl->wn;
	    }
	  /* if(svl)... */
	}
      /* to next level */
    }

  /* needs more x space */
  svg_max_x_pos = (maxw + SVG_XSPACING + SVG_XOFFSET);
  /* update here for more y pos. algo's and make yspacing dynamic */
  maxly = 0;
  /* now scan the levels and set the y positions of nodes and levels */
  for (i = 0; i < dli_nlevels; i++)
    {
      spnl = splay_tree_lookup (svgjs_splevels, (splay_tree_key) i);
      svl = (struct svglev *) spnl->value;
      /* */
      if (svl)
	{
	  /* drawing starts at y offset */
	  h = SVG_YOFFSET;
	  /* list of all nodes in this level: dummy+real+edgelabel nodes, indexed on position */
	  if (splay_tree_has_data (svl->spnlist))
	    {
	      /* scan the nodes in this level */
	      spn = splay_tree_min (svl->spnlist);
	      /* foreach() on the splay spnlist */
	      while (spn)
		{
		  /* uniq node number is in spn->value */
		  spnn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) spn->value);
		  /* get node data */
		  svn = (struct svgnode *) spnn->value;
		  /* check y size of node */
		  if (svn->bby > h)
		    {
		      h = svn->bby;
		    }
		  /* to next node in this level */
		  spn = splay_tree_successor (svl->spnlist, spn->key);
		}
	      /* save y size of this level */
	      svl->hn = (h + SVG_YSPACING);
	      /* */
	      if (option_gdebug)
		{
		  printf ("%s(): level %d has y-size %d, highest level has %d pixels\n", __FUNCTION__, i, h, maxly);
		  fflush (stdout);
		}
	    }
	  else
	    {
	      if (option_gdebug)
		{
		  printf ("%s(): level %d has no nodes, highest level has %d pixels\n", __FUNCTION__, i, maxly);
		  fflush (stdout);
		}
	      /* save height ysize of this level with its offset */
	      svl->hn = (h + SVG_YSPACING);
	    }
	  /* check max */
	  if (h > maxly)
	    {
	      /* set new max y */
	      maxly = h;
	    }
	  /* if(svl)... */
	}
      /* to next level */
    }

  /* re-scan nodes and set the y pos of nodes */
  h = SVG_YOFFSET;
  /* determine (x,y) max. and x is set above. */
  svg_max_y_pos = 0;
  /* now scan the levels and set the y positions of nodes and levels */
  for (i = 0; i < dli_nlevels; i++)
    {
      spnl = splay_tree_lookup (svgjs_splevels, (splay_tree_key) i);
      svl = (struct svglev *) spnl->value;
      /* drawing starts at y offset */
      svl->y0 = h;
      /* list of all nodes in this level: dummy+real+edgelabel nodes, indexed on position */
      if (splay_tree_has_data (svl->spnlist))
	{
	  /* scan the nodes in this level */
	  spn = splay_tree_min (svl->spnlist);
	  /* foreach() on the splay spnlist */
	  while (spn)
	    {
	      /* uniq node number is in spn->value */
	      spnn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) spn->value);
	      /* */
	      if (spnn)
		{
		  /* get node data */
		  svn = (struct svgnode *) spnn->value;
		  /* update it in the nodes */
		  delta = (svl->hn - svn->bby);
		  delta = (delta / 2);
		  /* set top/bottom of node */
		  svn->y0 = h;
		  svn->y1 = (svl->y0 + delta);
		  svn->y2 = (svl->y0 + delta + svn->bby);
		  svn->y3 = (h + svl->hn);
		}
	      /* to next node in this level */
	      spn = splay_tree_successor (svl->spnlist, spn->key);
	    }
	}
      else
	{
	  printf ("%s(): level %d has no nodes, starts at y %d, y size %d, highest level has %d pixels\n", __FUNCTION__, i, svl->y0, svl->hn, maxly);
	  fflush (stdout);
	  /* save height ysize of this level with its offset */
	  svl->y0 = h;
	  /* give empty level some room */
	  svl->hn = SVG_YSPACING;
	}
      /* set edge area y size and move to next level */
      svl->he = SVG_YSPACING;
      /* start y + edge area y size + node area y size */
      h = (svl->y0 + svl->he + svl->hn);
      /* check max y pos */
      if (h >= svg_max_y_pos)
	{
	  svg_max_y_pos = h;
	}
      /* to next level */
    }

  /* add extra y space */
  svg_max_y_pos = (svg_max_y_pos + SVG_YOFFSET);
  /*  */
  if (option_gdebug)
    {
      printf ("%s(): drawing has size (%d,%d)\n", __FUNCTION__, svg_max_x_pos, svg_max_y_pos);
      fflush (stdout);
    }

  /* header are the sub-parts, see strings above */
  fprintf (f, "%s\n", head0);
  fprintf (f, "%s\n", head1);
  fprintf (f, HEAD2, svg_max_x_pos, svg_max_y_pos);
  fprintf (f, "%s\n", head3);
  fprintf (f, "%s\n", head4);
  fprintf (f, "%s\n", head5);
  fprintf (f, "%s\n", head55);
  fprintf (f, "%s\n", head56);
  fprintf (f, "%s\n", head6);
  fprintf (f, "%s\n", head7);
  fprintf (f, "%s\n", head8);


  fprintf (f, HEAD9, SVG_FONTNAME, SVG_POINTSIZE);
  fprintf (f, "%s\n", head10);
  fprintf (f, "%s\n", head11);
  fprintf (f, "%s\n", head12);
  fprintf (f, "%s\n", head13);
  fprintf (f, "%s\n", head14);
  fprintf (f, "%s\n", head15);
  /* print a header line with program name and version info */
  fprintf (f, "<!-- use this svg with firefox browser and this is generated by %s at %s drawing size (%d,%d) -->\n",
	   PACKAGE_STRING, PACKAGE_URL, svg_max_x_pos, svg_max_y_pos);
  /* update this part can be made complex with more features */
  /* now scan the levels and generate draw data */
  for (i = 0; i < dli_nlevels; i++)
    {
      spnl = splay_tree_lookup (svgjs_splevels, (splay_tree_key) i);
      /* */
      if (spnl)
	{
	  svl = (struct svglev *) spnl->value;
	  /* list of all nodes in this level: dummy+real+edgelabel nodes, indexed on position */
	  if (splay_tree_has_data (svl->spnlist))
	    {
	      /* scan the nodes in this level */
	      spn = splay_tree_min (svl->spnlist);
	      /* foreach() on the splay spnlist indexed on relative level */
	      while (spn)
		{
		  /* uniq node number is in spn->value */
		  spnn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) spn->value);
		  /* get node data */
		  svn = (struct svgnode *) spnn->value;
		  /* check */
		  if (svn->un->level != i)
		    {
		      printf ("%s(): node is at level %d but seen at level %d\n", __FUNCTION__, svn->un->level, i);
		      fflush (stdout);
		    }
		  /* node coords. are in svn and in svl */
		  if (svn->un->label)
		    {
		      /* this is a real node */
		      /* a "--" is in a xml comment not allowed, have to filter label on a -- sequence */
		      fprintf (f, "<!-- node %d %s at relative (%d,%d) level=%d abs pos (%d,%d) size (%d,%d) label=\"\n",
			       svn->un->number, svn->un->name, svn->un->pos, svn->un->level, i, svn->x0, svn->y1, svn->bbx, svn->bby);
		      /* print the label text with modified -- sequence */
		      p = svn->un->label;
		      c = 0;
		      while ((*p))
			{
			  /* check for a -- sequence and change in - - */
			  if ((*p) == '-')
			    {
			      if (c == '-')
				{
				  /* add a space between the -- to make it - - */
				  fputc (' ', f);
				}
			    }
			  fputc ((*p), f);
			  c = (*p);
			  /* to next char in string */
			  p = (p + 1);
			}
		      fprintf (f, "%s\n", "\" -->");
		    }
		  else
		    {
		      /* this is a dummy node */
		      fprintf (f,
			       "<!-- node %d %s at relative (%d,%d) level=%d abs pos (%d,%d) size (%d,%d) dummy-node-has-no-label -->\n",
			       svn->un->number, svn->un->name, svn->un->pos, svn->un->level, i, svn->x0, svn->y1, svn->bbx, svn->bby);
		    }
		  /* determine degree of nodes but only connections to real nodes */
		  usepoe = svn->un->sp_poe;
		  if (splay_tree_has_data (usepoe))
		    {
		      usepoe = svn->un->sp_poe;
		      spn0 = splay_tree_min (usepoe);
		      while (spn0)
			{
			  ue0 = (struct uedge *) spn0->value;
			  /* check incoming edges */
			  if (ue0->tn == svn->un)
			    {
			      /* real+dummy nodes degree */
			      svn->indegree = (svn->indegree + 1);
			    }
			  else
			    {
			      /* real+dummy nodes degree */
			      svn->outdegree = (svn->outdegree + 1);
			    }
			  spn0 = splay_tree_successor (usepoe, spn0->key);
			}
		    }
		  else
		    {
		      /* no edge connections */
		      svn->indegree = 0;
		      svn->outdegree = 0;
		    }
		  /* to next node in this level */
		  spn = splay_tree_successor (svl->spnlist, spn->key);
		}
	    }
	  else
	    {
	      /* there are no nodes at this level */
	    }
	  /* if(spnl)... */
	}
      /* to next level */
    }

  /* now scan the levels and prepare draw data */

  /* memory tracking splay tree */
  svgjs_mt = splay_tree_new (splay_tree_compare_pointers, on_top_level_window_saveassvgjs1_activate3_free, NULL);
  /* counter for starts */
  j = 1;
  /* scan all levels */
  for (i = 0; i < dli_nlevels; i++)
    {
      spnl = splay_tree_lookup (svgjs_splevels, (splay_tree_key) i);
      /* */
      if (spnl)
	{
	  svl = (struct svglev *) spnl->value;
	  /* list of all nodes in this level: dummy+real+edgelabel nodes, indexed on position */
	  if (splay_tree_has_data (svl->spnlist))
	    {
	      /* scan the nodes in this level */
	      spn = splay_tree_min (svl->spnlist);
	      /* foreach() on the splay spnlist indexed on relative level */
	      while (spn)
		{
		  /* uniq node number is in spn->value */
		  spnn = splay_tree_lookup (svgjs_spnodes, (splay_tree_key) spn->value);
		  /* get node data */
		  svn = (struct svgnode *) spnn->value;
		  /* node coords. are in svn and in svl */
		  if (svn->un->label)
		    {
		      /* this is a real node */
		      if (svn->indegree == 0)
			{
			  /* new data to pass on */
			  psvel = mymalloc (sizeof (struct svgel), __FUNCTION__, __LINE__);
			  /* register this malloc */
			  splay_tree_insert (svgjs_mt, (splay_tree_key) psvel, (splay_tree_value) sizeof (struct svgel));
			  /* set rooted on rootgraph */
			  psvel->rootedon = (struct svgel *) 0;
			  /* create id name to use appending a _1 or _number */
			  memset (elbuf, 0, 8);
			  snprintf (elbuf, (8 - 1), "_1_%d", j);
			  psvel->id = uniqstring ((char *) elbuf);
			  /* set node info */
			  psvel->sn = svn;
			  /* set edge info */
			  psvel->ue = (struct uedge *) 0;
			  /* init empty linkage */
			  psvel->svel = (struct svgel *) 0;
			  psvel->svel_end = (struct svgel *) 0;
			  /* add in linkage */
			  if (svel_end == NULL)
			    {
			      /* first entry */
			      svel = psvel;
			      svel_end = psvel;
			    }
			  else
			    {
			      /* chain on */
			      svel_end->next = psvel;
			      svel_end = psvel;
			    }
			  /* node is a start node in the graph and scan now */
			  on_top_level_window_saveassvgjs1_activate4 (psvel);
			  /* to next start node */
			  j = (j + 1);
			}
		      else
			{
			  /* node is a middle or end node in the graph */
			}
		    }
		  else
		    {
		      /* this is a dummy node */
		    }
		  /* to next node in this level */
		  spn = splay_tree_successor (svl->spnlist, spn->key);
		}
	    }
	  else
	    {
	      /* there are no nodes at this level */
	    }
	  /* if(spnl)... */
	}
      /* to next level */
    }

  /* write svg to file and node is a start node in the graph and scan now */
  psvel = svel;
  /* */
  while (psvel)
    {
      on_top_level_window_saveassvgjs1_activate5 (f, psvel);
      psvel = psvel->next;
    }

  /* finally clear all extra memory used to generate the svg */

  /* clear node data splay trees */
  svgjs_spnodes = splay_tree_delete (svgjs_spnodes);

  /* free levels data with nested splay tree */
  for (i = 0; i < dli_nlevels; i++)
    {
      spn = splay_tree_lookup (svgjs_splevels, (splay_tree_value) i);
      svl = (struct svglev *) spn->value;
      /* this is the nested splay tree to free */
      /* not a free() but splay_tree_delete() which does the free() */
      svl->spnlist = splay_tree_delete (svl->spnlist);
    }

  /* free level data and the splay tree itself */
  svgjs_splevels = splay_tree_delete (svgjs_splevels);
  /* clear memory tracking splay tree */
  svgjs_mt = splay_tree_delete (svgjs_mt);

  /* ready */
  return;
}

/* write the svg body to file */
static void
on_top_level_window_saveassvgjs1_activate2 (char *fname)
{
  char *head99 = "</svg>";
  FILE *f = NULL;
  /* check fname */
  if (fname == NULL)
    {
      /* should not happen */
      return;
    }
  if (strlen (fname) == 0)
    {
      /* should not happen */
      return;
    }

  /* create the output file, gtk asked to overwrite is existed already */
  f = fopen (fname, "wb");
  if (f == NULL)
    {
      /* should not happen */
      return;
    }

  /* write the node+edge data */
  on_top_level_window_saveassvgjs1_activate3 (f);
  /* add the close svg tag */
  fprintf (f, "%s\n", head99);
  /* ready with file */
  fclose (f);
  /* ready */
  return;
}

/*
 * end of the svg+javascript output
 */

/* save as svg document (+js) */
void
on_top_level_window_saveassvgjs1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *svgjsfilename = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  char *sfn = NULL;
  if (menuitem)
    {
    }

  if (user_data)
    {
    }

  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As svg with javascript",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  /* change to last used dir if any */
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  /* ask to override existing image */
  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
  /* get the filename */
  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      svgjsfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      /* no filename */
      return;
    }

  /* check save file name */
  sfn = valid_save_filename (svgjsfilename);
  /* generate it */
  on_top_level_window_saveassvgjs1_activate2 (sfn);
  /* clear strdup'ed name - must be free(), not myfree() */
  free (svgjsfilename);
  svgjsfilename = NULL;
  return;
}

/***zz6***save svg***/

/* to update: cairo has a xml output surface. another output driver. to use like this:
 * #ifdef CAIRO_HAS_XML_SURFACE
 * static cairo_status_t
 * r_cairo_write_func (void *closure, const unsigned char *data, unsigned int length)
 * {
 *    if (fwrite (data, 1, length, (FILE *) closure) == length)
 *        return CAIRO_STATUS_SUCCESS;
 *    return CAIRO_STATUS_WRITE_ERROR;
 * }
 * FILE *output_file
 * cairo_device_t *device = cairo_xml_create_for_stream (r_cairo_write_func, output_file);
 * surface = cairo_xml_surface_create (device, CAIRO_CONTENT_COLOR_ALPHA,dimensions.width, dimensions.height);
 */

/* save as svg document (gtk) */
void
on_top_level_window_saveassvg1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *svgfilename = NULL;
  cairo_surface_t *surface = NULL;
  cairo_t *crp = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  int i = 0;
  int mymaxx = 0;
  int mymaxy = 0;
  int saved_vxmin = 0;
  int saved_vymin = 0;
  char *sfn = NULL;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }
  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As svg",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  /* change to last used dir if any */
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  /* ask to override existing image */
  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
  /* get the filename */
  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      svgfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      /* no filename */
      return;
    }

  /* save current gui settings */
  saved_vxmin = vxmin;
  saved_vymin = vymin;

  /* output whole drawing */
  vxmin = 0;
  vymin = 0;
  mymaxx = (int) (maxx * zfactor);
  mymaxy = (int) (maxy * zfactor);

  /* check save file name */
  sfn = valid_save_filename (svgfilename);
  /* */
  surface = cairo_svg_surface_create (sfn, mymaxx, mymaxy);
  /* */
  crp = cairo_create (surface);
  /* fill drawing background with background color */
  if (altcolor)
    {
      /* set background to white in alt color mode */
      cairo_set_source_rgb (crp, 0x00ffffff / 255.0, 0x00ffffff / 255.0, 0x00ffffff / 255.0);
    }
  else
    {
      cairo_set_source_rgb (crp, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
    }

  /* select whole drawing to fill wth background color */
  cairo_rectangle (crp, 0, 0, mymaxx, mymaxy);
  cairo_fill (crp);
  /* use zoom slider drawing scale */
  cairo_scale (crp, zfactor, zfactor);
  /* mark all layers to draw */
  for (i = 0; i < dli_nlevels; i++)
    {
      dlip[i]->draw = 1;
    }

  /* draw node/edge data in the draw lists */
  on_top_level_window_drawingarea1_expose_event_subgrapharea (crp);
  on_top_level_window_drawingarea1_expose_event_nodes (crp);
  on_top_level_window_drawingarea1_expose_event_edges (crp);
  /* clear strdup'ed name - must be free(), not myfree() */
  free (svgfilename);
  svgfilename = NULL;
  /* */
  cairo_destroy (crp);
  cairo_surface_destroy (surface);
  /* restore screen (x,y) min */
  vxmin = saved_vxmin;
  vymin = saved_vymin;
  return;
}

/* called from main() when running as console tool generating svg image */
void
maingtk_saveassvg (char *infile, char *outfile)
{
  FILE *ff = NULL;
  int dounlink = 0;
  int i = 0;
  char *sfn = NULL;
  cairo_surface_t *surface = NULL;
  cairo_t *crp = NULL;
  char *svgfilename = NULL;
  int status = 0;
  int mymaxx = 0;
  int mymaxy = 0;
  /* parse file as specified with commandline options */
  parse (infile);
  /* if file did not parse no output */
  if (splay_tree_has_data (sp_parsednl) == 0)
    {
      return;
    }
  svgfilename = strdup (outfile);
  /* calculate on the initial graph */
  calculate_init ();
  /* un-fold all subgraphs */
  folding_all (0);
  /* calculate the graph */
  calculate ();
  /* zoom to default 100% */
  zfactor = 1.0;
  /* whole drawing */
  vxmin = 0;
  vymin = 0;
  /* normal color drawing mode */
  altcolor = 0;
  /* draw node and edge data if valid data */
  drawnldata = drawnl;
  draweldata = drawel;
  /* check if something to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  /* output whole drawing */
  vxmin = 0;
  vymin = 0;
  mymaxx = (int) (maxx * zfactor);
  mymaxy = (int) (maxy * zfactor);

  /* toedoe: for svg in dryrun can also easier write to /dev/null (linux only) now it writes file then deletes it */

  /* check save file name */
  sfn = valid_save_filename (svgfilename);

  /* try /dev/null */
  if (option_dryrun)
    {
      ff = fopen ("/dev/null", "wb");
      if (ff)
	{
	  /* /dev/null exists */
	  fclose (ff);
	  dounlink = 0;
	  surface = cairo_svg_surface_create ("/dev/null", mymaxx, mymaxy);
	}
      else
	{
	  /* no /dev/null, create file to delete */
	  surface = cairo_svg_surface_create (sfn, mymaxx, mymaxy);
	  dounlink = 1;
	}
    }
  else
    {
      /* create regular file to keep */
      surface = cairo_svg_surface_create (sfn, mymaxx, mymaxy);
    }

  /* */
  crp = cairo_create (surface);

  /* smaller 16 bits per pixel does not work with cairo lib
   * surface = cairo_image_surface_create (CAIRO_FORMAT_RGB16_565, maxx, maxy);
   */

  if (surface == NULL)
    {
      printf ("%s(): no surface (%d,%d)\n", __FUNCTION__, maxx, maxy);
      return;
    }

  /* fill drawing background with background color */
  cairo_set_source_rgb (crp, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
  cairo_rectangle (crp, 0, 0, maxx, maxy);
  cairo_fill (crp);
  /* use zoom drawing scale */
  cairo_scale (crp, zfactor, zfactor);
  /* mark all layers to draw */
  for (i = 0; i < dli_nlevels; i++)
    {
      dlip[i]->draw = 1;
    }

  /* at dryrun mode at testing with -Z or --Z option
   * do everything but no actual svg image writing
   */
  if (option_dryrun)
    {
      /* skip */
      printf ("%s(): skipped svg image %s with size (%d,%d) %d nodes, %d edges, %d levels, %d start-crossings, %d end-crossings\n", __FUNCTION__, outfile,
	      maxx, maxy,
	      /* drawing nodes */
	      n_drawing_nodes,
	      /* drawing edges */
	      n_drawing_edges,
	      /* number of levels */
	      dli_nlevels,
	      /* start crossings */
	      get_begin_crossings (),
	      /* end crossings */
	      get_end_crossings ());

      /* draw node/edge data in the draw lists */
      on_top_level_window_drawingarea1_expose_event_subgrapharea (crp);
      on_top_level_window_drawingarea1_expose_event_nodes (crp);
      on_top_level_window_drawingarea1_expose_event_edges (crp);

      /* do not unlink /dev/null */
      if (dounlink)
	{
	  status = unlink (sfn);

	  if (status)
	    {
	      printf ("%s(): unlink error status %d for file %s\n", __FUNCTION__, status, sfn);
	    }
	}

      /* clear strdup'ed name - must be free(), not myfree() */
      free (svgfilename);
      svgfilename = NULL;

      /* */
      cairo_destroy (crp);
      cairo_surface_destroy (surface);
    }
  else
    {
      /* draw node/edge data in the draw lists */
      on_top_level_window_drawingarea1_expose_event_subgrapharea (crp);
      on_top_level_window_drawingarea1_expose_event_nodes (crp);
      on_top_level_window_drawingarea1_expose_event_edges (crp);

      /* clear strdup'ed name - must be free(), not myfree() */
      free (svgfilename);
      svgfilename = NULL;

      /* */
      cairo_destroy (crp);
      cairo_surface_destroy (surface);
    }

  return;
}

/***zz7***save pdf ***/

/* save as pdf document */
void
on_top_level_window_saveaspdf1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *pdffilename = NULL;
  cairo_surface_t *surface = NULL;
  cairo_t *crp = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  int i = 0;
  int mymaxx = 0;
  int mymaxy = 0;
  int saved_vxmin = 0;
  int saved_vymin = 0;
  char *sfn = NULL;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }
  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As Pdf",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);
  /* change to last used dir if any */
  if (lastdir)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir);
    }

  /* ask to override existing image */
  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
  /* get the filename */
  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      pdffilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      /* no filename */
      return;
    }

  /* save current gui settings */
  saved_vxmin = vxmin;
  saved_vymin = vymin;
  /* output whole drawing */
  vxmin = 0;
  vymin = 0;
  mymaxx = (int) (maxx * zfactor);
  mymaxy = (int) (maxy * zfactor);
  /* check save file name */
  sfn = valid_save_filename (pdffilename);
  /* */
  surface = cairo_pdf_surface_create (sfn, mymaxx, mymaxy);
  /* */
  crp = cairo_create (surface);
  /* fill drawing background with background color */
  if (altcolor)
    {
      /* set background to white in alt color mode */
      cairo_set_source_rgb (crp, 0x00ffffff / 255.0, 0x00ffffff / 255.0, 0x00ffffff / 255.0);
    }
  else
    {
      cairo_set_source_rgb (crp, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
    }
  cairo_rectangle (crp, 0, 0, mymaxx, mymaxy);
  cairo_fill (crp);
  /* use zoom slider drawing scale */
  cairo_scale (crp, zfactor, zfactor);
  /* mark all layers to draw */
  for (i = 0; i < dli_nlevels; i++)
    {
      dlip[i]->draw = 1;
    }

  /* draw node/edge data in the draw lists */
  on_top_level_window_drawingarea1_expose_event_subgrapharea (crp);
  on_top_level_window_drawingarea1_expose_event_nodes (crp);
  on_top_level_window_drawingarea1_expose_event_edges (crp);
  /* */
  cairo_show_page (crp);
  /* clear strdup'ed name - must be free(), not myfree() */
  free (pdffilename);
  pdffilename = NULL;
  /* */
  cairo_destroy (crp);
  cairo_surface_destroy (surface);
  /* restore screen (x,y) min */
  vxmin = saved_vxmin;
  vymin = saved_vymin;
  return;
}

/***zz8***save png***/

/* save as png image */
void
on_top_level_window_saveaspng1_activate (GtkMenuItem * menuitem, gpointer user_data)
{
  GtkWidget *dialog = (GtkWidget *) 0;
  char *file_chooser_filename = (char *) 0;
  char *pngfilename = NULL;
  cairo_surface_t *surface = NULL;
  cairo_t *crp = NULL;
  GtkFileChooser *chooser = NULL;
  GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  gint res = 0;
  int i = 0;
  int mymaxx = 0;
  int mymaxy = 0;
  int saved_vxmin = 0;
  int saved_vymin = 0;
  char *sfn = NULL;
  if (menuitem)
    {
    }
  if (user_data)
    {
    }
  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  mymaxx = (int) (maxx * zfactor);
  mymaxy = (int) (maxy * zfactor);

  /* it looks like cairo lib has png max 32k pixels size */
  if ((mymaxx >= (32 * 1024)) || (mymaxy >= (32 * 1024)))
    {
      fprintf (stderr, "%s(): image size (%d,%d) too big max. 32k, scale down or use svg\n", __FUNCTION__, mymaxx, mymaxy);
      fflush (stderr);
      return;
    }

  dialog = gtk_file_chooser_dialog_new ("Save As Png",
					/* parent_window */ NULL,
					action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  chooser = GTK_FILE_CHOOSER (dialog);

  /* change to last used dir if any */
  if (lastdir2)
    {
      gtk_file_chooser_set_current_folder (chooser, lastdir2);
    }

  /* ask to override existing image */
  gtk_file_chooser_set_do_overwrite_confirmation (chooser, TRUE);
  /* get the filename */
  gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (mainwindow1));

  res = gtk_dialog_run (GTK_DIALOG (dialog));
  if (res == GTK_RESPONSE_ACCEPT)
    {
      file_chooser_filename = gtk_file_chooser_get_filename (chooser);
      lastdir2 = gtk_file_chooser_get_current_folder (chooser);
    }
  else
    {
      /* cancel button */
      (void) gtk_widget_destroy (dialog);
      return;
    }

  /* */
  (void) gtk_widget_destroy (dialog);
  /* */
  if (file_chooser_filename)
    {
      pngfilename = strdup (file_chooser_filename);
      /* */
      (void) g_free (file_chooser_filename);
    }
  else
    {
      /* no filename */
      return;
    }

  /* save current gui settings */
  saved_vxmin = vxmin;
  saved_vymin = vymin;
  /* output whole drawing */
  vxmin = 0;
  vymin = 0;
  mymaxx = (int) (maxx * zfactor);
  mymaxy = (int) (maxy * zfactor);
  /* */
  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, mymaxx, mymaxy);
  /* */
  crp = cairo_create (surface);

  /* fill drawing background with background color */
  if (altcolor)
    {
      /* set background to white in alt color mode */
      cairo_set_source_rgb (crp, 0x00ffffff / 255.0, 0x00ffffff / 255.0, 0x00ffffff / 255.0);
    }
  else
    {
      cairo_set_source_rgb (crp, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
    }
  cairo_rectangle (crp, 0, 0, mymaxx, mymaxy);
  cairo_fill (crp);
  /* use zoom slider drawing scale */
  cairo_scale (crp, zfactor, zfactor);
  /* mark all layers to draw */
  for (i = 0; i < dli_nlevels; i++)
    {
      dlip[i]->draw = 1;
    }

  /* draw node/edge data in the draw lists */
  on_top_level_window_drawingarea1_expose_event_subgrapharea (crp);
  on_top_level_window_drawingarea1_expose_event_nodes (crp);
  on_top_level_window_drawingarea1_expose_event_edges (crp);
  /* check save file name */
  sfn = valid_save_filename (pngfilename);
  /* */
  cairo_surface_write_to_png (surface, sfn);
  /* clear strdup'ed name - must be free(), not myfree() */
  free (pngfilename);
  pngfilename = NULL;
  /* */
  cairo_destroy (crp);
  cairo_surface_destroy (surface);
  /* restore screen (x,y) min */
  vxmin = saved_vxmin;
  vymin = saved_vymin;
  return;
}

/* called from main() when running as console tool generating png image.
 * dot has bgcolor=transparent for output of transparent background.
 * cairo_surface_write_to_png() is a toy api and for more control of
 * the output png use of the data and pnglib is needed.
 */
void
maingtk_saveaspng (char *infile, char *outfile)
{
  int i = 0;
  cairo_surface_t *surface = NULL;
  cairo_t *crp = NULL;
  cairo_status_t pngstatus = 0;

  /* parse file as specified with commandline options */
  parse (infile);

  /* if file did not parse no output */
  if (splay_tree_has_data (sp_parsednl) == 0)
    {
      return;
    }

  /* calculate on the initial graph */
  calculate_init ();

  /* un-fold all subgraphs */
  folding_all (0);

  /* calculate the graph */
  calculate ();

  /* zoom to default 100% */
  zfactor = 1.0;

  /* whole drawing */
  vxmin = 0;
  vymin = 0;

  /* normal color drawing mode */
  altcolor = 0;

  /* draw node and edge data if valid data */
  drawnldata = drawnl;
  draweldata = drawel;

  /* check if something to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  /* it looks like cairo lib has png max 32k pixels size */
  if ((maxx >= (32 * 1024)) || (maxy >= (32 * 1024)))
    {
      /* XXX or change zfactor to smaller and try to generate drawing */
      fprintf (stderr,
	       "%s(): skipped too big png image %s with size (%d,%d) %d nodes, %d edges, %d levels, %d start-crossings, %d end-crossings try svg output\n",
	       __FUNCTION__, outfile, maxx, maxy,
	       /* drawing nodes */
	       n_drawing_nodes,
	       /* drawing edges */
	       n_drawing_edges,
	       /* number of levels */
	       dli_nlevels,
	       /* start crossings */
	       get_begin_crossings (),
	       /* end crossings */
	       get_end_crossings ());
      fflush (stderr);
      return;
    }

  /* big image data */
  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, maxx, maxy);

  /* smaller 16 bits per pixel does not work with cairo lib
   * surface = cairo_image_surface_create (CAIRO_FORMAT_RGB16_565, maxx, maxy);
   */

  if (surface == NULL)
    {
      printf ("%s(): no surface (%d,%d)\n", __FUNCTION__, maxx, maxy);
      return;
    }

  /* */
  crp = cairo_create (surface);
  if (crp == NULL)
    {
      return;
    }

  /* fill drawing background with background color */
  cairo_set_source_rgb (crp, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
  cairo_rectangle (crp, 0, 0, maxx, maxy);
  cairo_fill (crp);
  /* use zoom drawing scale */
  cairo_scale (crp, zfactor, zfactor);
  /* mark all layers to draw */
  for (i = 0; i < dli_nlevels; i++)
    {
      dlip[i]->draw = 1;
    }

  /* draw node/edge data in the draw lists */
  on_top_level_window_drawingarea1_expose_event_subgrapharea (crp);
  cairo_stroke (crp);
  on_top_level_window_drawingarea1_expose_event_nodes (crp);
  cairo_stroke (crp);
  on_top_level_window_drawingarea1_expose_event_edges (crp);
  cairo_stroke (crp);

  /* at dryrun mode at testing with -Z or --Z option
   * do everything but no actual png image writing
   */
  if (option_dryrun)
    {
      /* skip */
      printf ("%s(): skipped png image %s with size (%d,%d) %d nodes, %d edges, %d levels, %d start-crossings, %d end-crossings\n", __FUNCTION__, outfile,
	      maxx, maxy,
	      /* drawing nodes */
	      n_drawing_nodes,
	      /* drawing edges */
	      n_drawing_edges,
	      /* number of levels */
	      dli_nlevels,
	      /* start crossings */
	      get_begin_crossings (),
	      /* end crossings */
	      get_end_crossings ());
    }
  else
    {
      /* upper limit on image width or height is thus 2^31-1 or 2,147,483,647
       * cairo_surface_write_to_png ()
       * cairo_status_t
       * cairo_surface_write_to_png (cairo_surface_t *surface, const char *filename);
       * Writes the contents of surface to a new file filename as a PNG image.
       * Parameters
       * surface a cairo_surface_t with pixel contents
       * filename the name of a file to write to
       * Returns
       * CAIRO_STATUS_SUCCESS if the PNG file was written successfully.
       * CAIRO_STATUS_NO_MEMORY if memory could not be allocated for the operation
       * CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have pixel contents
       * CAIRO_STATUS_WRITE_ERROR if an I/O error occurs while attempting to write the file.
       */
      /* assume outfile name is oke to use from command line */

      /* actual write the image may cause crash:
       * /lib/x86_64-linux-gnu/libc.so.6(+0x92040)[0x7f0a5d572040]
       * /lib/x86_64-linux-gnu/libpng12.so.0(png_write_row+0x113)[0x7f0a5a500d63]
       * /lib/x86_64-linux-gnu/libpng12.so.0(png_write_image+0x48)[0x7f0a5a500fe8]
       * /usr/lib/x86_64-linux-gnu/libcairo.so.2(+0xb14a9)[0x7f0a5e9564a9]
       * /usr/lib/x86_64-linux-gnu/libcairo.so.2(cairo_surface_write_to_png+0x42)[0x7f0a5e956d62]
       */
      pngstatus = cairo_surface_write_to_png (surface, outfile);
      switch (pngstatus)
	{
	case CAIRO_STATUS_SUCCESS:
	  /* if the PNG file was written successfully. */
	  break;
	case CAIRO_STATUS_NO_MEMORY:
	  /* if memory could not be allocated for the operation */
	  printf ("%s(): no memory to write image file %s\n", __FUNCTION__, outfile);
	  fflush (stdout);
	  break;
	case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
	  /* if the surface does not have pixel contents */
	  printf ("%s(): no image pixels for file %s\n", __FUNCTION__, outfile);
	  fflush (stdout);
	  break;
	case CAIRO_STATUS_WRITE_ERROR:
	  /* if an I/O error occurs while attempting to write the file. */
	  printf ("%s(): write error at image file %s\n", __FUNCTION__, outfile);
	  fflush (stdout);
	  break;
	default:
	  /* status number 32 value too big error */
	  printf ("%s(): unknown status %d %s from cairo_surface_write_to_png shouldnothappen at image file %s size (%d,%d) pixels\n", __FUNCTION__,
		  (int) pngstatus, cairo_status_to_string (pngstatus), outfile, maxx, maxy);
	  fflush (stdout);
	  break;
	}

    }

  /* */
  cairo_destroy (crp);
  cairo_surface_destroy (surface);

  return;
}


/***zz9***treeview window***/

/* clicked on node and center node on screen if possible */
static void
treeview_center_node (struct unode *un)
{
  gint w = 0;
  gint h = 0;
  int hw = 0;
  int hh = 0;
  int nx = 0;
  int ny = 0;
  double dhw = 0.0;
  double gdelta = 0.0;
  double gsld = 0.0;
  double val = 0.0;
  int ival = 0;
  double dx = 0.0;
  double dy = 0.0;
  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  /* check node */
  if (un == NULL)
    {
      return;
    }

  if (un->bitflags.dummynode == 1)
    {
      return;
    }

  if (un->bitflags.edgelabel == 1)
    {
      return;
    }

  if (un->bitflags.sumnode == 1)
    {
      return;
    }

  /* check if node is in drawing */
  if (un->bitflags.visible == 0)
    {
      return;
    }

  /* center of node */
  dx = (un->x1 / zfactor);
  dy = ((un->y1 + (un->bby / 2)) / zfactor);
  /* how large drawing area is gtk-2.0 */
#if GTK_HAVE_API_VERSION_2
  (void) gdk_drawable_get_size (drawingarea1->window, &w, &h);
#endif
  /* how large drawing area is */
#if GTK_HAVE_API_VERSION_3
  w = gtk_widget_get_allocated_width (drawingarea1);
  h = gtk_widget_get_allocated_height (drawingarea1);
#endif
  /* center of drawing area */
  hw = w / 2;
  hh = h / 2;
  if (nx < maxx)
    {
      dhw = (hw + vxmin) / zfactor;
      gdelta = dx - dhw;
      vxmin = vxmin + (int) gdelta;
      if (vxmin < 0)
	{
	  vxmin = 0;
	}
      gsld = gdelta;
      gsld = gdelta / maxx;
      gsld = gsld * 100;
      val = gtk_adjustment_get_value (GTK_ADJUSTMENT (adjhscale1));
      ival = (int) val;
      ival = ival + (int) gsld;
      if (ival < 0)
	{
	  ival = 0;
	}
      if (ival > 100)
	{
	  ival = 100;
	}
      gtk_adjustment_set_value (GTK_ADJUSTMENT (adjhscale1), ival);
    }

  if (ny < maxy)
    {
      dhw = (hh + vymin) / zfactor;
      gdelta = dy - dhw;
      vymin = vymin + (int) gdelta;
      if (vymin < 0)
	{
	  vymin = 0;
	}
      gsld = gdelta;
      gsld = gdelta / maxy;
      gsld = gsld * 100;
      val = gtk_adjustment_get_value (GTK_ADJUSTMENT (adjvscale2));
      ival = (int) val;
      ival = ival + (int) gsld;
      if (ival < 0)
	{
	  ival = 0;
	}
      if (ival > 100)
	{
	  ival = 100;
	}
      gtk_adjustment_set_value (GTK_ADJUSTMENT (adjvscale2), ival);
    }

  /* only redraw needed */
  gtk_widget_queue_draw (drawingarea1);
  return;
}

/* treeview changed */
static void
treeview_on_changed (GtkWidget * widget, gpointer statusbar)
{
  GtkTreeIter iter;
  GtkTreeModel *model = NULL;
  char *value = NULL;
  struct usubg *subg = NULL;
  struct unode *un = NULL;
  struct uedge *ue = NULL;
  GtkTextBuffer *tbuffer = NULL;
  const char *text = NULL;
  const char *label = NULL;
  char buf[1024];
  /* */
  if (gtk_tree_selection_get_selected (GTK_TREE_SELECTION (widget), &model, &iter))
    {
      /* get string of selected node in value */
      gtk_tree_model_get (model, &iter, 0, &value, 1, &subg, 2, &un, 3, &ue, -1);
      text = "";
      /* Obtaining the buffer associated with the widget. */
      tbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (treeviewtext_view));
      if (subg == NULL && un == NULL && ue == NULL)
	{
	  /* Set the default buffer text. */
	  gtk_text_buffer_set_text (tbuffer, "", -1);
	}
      else
	{
	  /* */
	  memset (buf, 0, 1024);
	  /* now follows text for subgraph, node or edge */
	  if (subg)
	    {
	      snprintf (buf, (1024 - 1), "subgraph %s\nlabel %s\n", subg->utf8name, subg->summaryn->utf8label);
	    }
	  else if (un)
	    {
	      if (un->label)
		{
		  label = un->utf8label;
		}
	      else
		{
		  /* dummy node has NULL label with size 0 */
		  label = "\"\"";
		}
	      snprintf (buf, (1024 - 1), "node %s\nlabel %s\nlevel %d\nshape %d", un->utf8name, label, un->level, un->bitflags.shape);
	      treeview_center_node (un);
	    }
	  else if (ue)
	    {
	      if (ue->label)
		{
		  label = ue->utf8label;
		}
	      else
		{
		  label = "\"\"";
		}
	      snprintf (buf, (1024 - 1), "edge %s->%s\n%s->%s\nedgelabel %s\n", ue->fn->utf8name, ue->tn->utf8name, ue->fn->utf8label,
			ue->tn->utf8label, label);
	    }
	  else
	    {
	      strcpy (buf, "shouldnothappen");
	    }
	  /* create fresh buffered text */
	  text = uniqstring (buf);
	  /* Set the default buffer text. */
	  gtk_text_buffer_set_text (tbuffer, text, -1);
	}

      /* put the string in the statusbar */
      gtk_statusbar_push (GTK_STATUSBAR (statusbar), gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar), value), value);
      g_free (value);
    }

  return;
}

/* */
static void
treeview_create_and_fill_model_rootnodes (GtkTreeStore * treestore, GtkTreeIter toplevel)
{
/*  struct dln *nptr = NULL;*/
  splay_tree_node spn = NULL;
  struct unode *un = NULL;
  char buf[55];
  char *text = NULL;
  GtkTreeIter child;		/* = ? */

  if (splay_tree_has_data (sp_parsednl))
    {

      spn = splay_tree_min (sp_parsednl);

      while (spn)
	{
	  un = (struct unode *) spn->value;
	  /* check for nodes rooted on rootgraph */
	  if (un->rootedon == NULL)
	    {
	      /* */
	      memset (buf, 0, 55);
	      snprintf (buf, (55 - 1), "%s", un->utf8name);
	      text = uniqstring (buf);
	      gtk_tree_store_append (treestore, &child, &toplevel);
	      gtk_tree_store_set (treestore, &child, 0, text, 1, NULL, 2, un, 3, NULL, -1);
	    }

	  /* next entry in splay tree */
	  spn = splay_tree_successor (sp_parsednl, spn->key);
	}

    }

  return;
}

/* */
static void
treeview_create_and_fill_model_rootedges (GtkTreeStore * treestore, GtkTreeIter toplevel)
{
  splay_tree_node spn = NULL;
  struct uedge *ue = NULL;
  char buff[25];
  char buft[25];
  char buf[55];
  char *text = NULL;
  GtkTreeIter child;

  if (splay_tree_has_data (sp_parsedel))
    {

      spn = splay_tree_min (sp_parsedel);

      while (spn)
	{
	  ue = (struct uedge *) spn->value;
	  /* check for both nodes in root graph */
	  if ((ue->fn->rootedon == NULL) && (ue->tn->rootedon == NULL))
	    {
	      memset (buff, 0, 25);
	      memset (buft, 0, 25);
	      memset (buf, 0, 55);
	      snprintf (buff, (25 - 1), "%s", ue->fn->utf8name);
	      snprintf (buft, (25 - 1), "%s", ue->tn->utf8name);
	      strcpy (buf, buff);
	      strcat (buf, "->");
	      strcat (buf, buft);
	      text = uniqstring (buf);
	      gtk_tree_store_append (treestore, &child, &toplevel);
	      gtk_tree_store_set (treestore, &child, 0, text, 1, NULL, 2, NULL, 3, ue, -1);
	    }
	  spn = splay_tree_successor (sp_parsedel, spn->key);
	}
    }

  return;
}

/* */
static void
treeview_create_and_fill_model_rootsubg (GtkTreeStore * treestore, GtkTreeIter toplevel, struct usubg *subg)
{
  char buff[25];
  char buft[25];
  char buf[55];
  char *text = NULL;
  GtkTreeIter child;
  GtkTreeIter child2;
  splay_tree_node spn = (splay_tree_node) 0;
  struct usubg *sg = (struct usubg *) 0;
  struct uedge *ue = (struct uedge *) 0;
  struct unode *un = (struct unode *) 0;
  memset (buf, 0, 55);
  snprintf (buf, 55 - 1, "sub %s", subg->summaryn->utf8label);
  text = uniqstring (buf);
  gtk_tree_store_append (treestore, &child, &toplevel);
  gtk_tree_store_set (treestore, &child, 0, text, 1, subg, 2, NULL, 3, NULL, -1);

  /* nodes in this subgraph */
  if (splay_tree_has_data (subg->sp_nl))
    {

      spn = splay_tree_min (subg->sp_nl);

      while (spn)
	{
	  un = (struct unode *) spn->value;
	  /* */
	  memset (buf, 0, 55);
	  snprintf (buf, 55 - 1, "%s", un->utf8name);
	  text = uniqstring (buf);
	  gtk_tree_store_append (treestore, &child2, &child);
	  gtk_tree_store_set (treestore, &child2, 0, text, 1, NULL, 2, un, 3, NULL, -1);
	  spn = splay_tree_successor (subg->sp_nl, spn->key);
	}
    }

  /* edges in this subgraph */
  if (splay_tree_has_data (subg->sp_el))
    {

      spn = splay_tree_min (subg->sp_el);

      while (spn)
	{
	  ue = (struct uedge *) spn->value;
	  memset (buff, 0, 25);
	  memset (buft, 0, 25);
	  memset (buf, 0, 55);
	  snprintf (buff, 25 - 1, "%s", ue->fn->utf8name);
	  snprintf (buft, 25 - 1, "%s", ue->tn->utf8name);
	  strcpy (buf, buff);
	  strcat (buf, "->");
	  strcat (buf, buft);
	  text = uniqstring (buf);
	  gtk_tree_store_append (treestore, &child2, &child);
	  gtk_tree_store_set (treestore, &child2, 0, text, 1, NULL, 2, NULL, 3, ue, -1);
	  spn = splay_tree_successor (subg->sp_el, spn->key);
	}

    }

  /* subgraphs of this subgraph */
  if (splay_tree_has_data (subg->sp_sg))
    {

      spn = splay_tree_min (subg->sp_sg);

      while (spn)
	{
	  sg = (struct usubg *) spn->value;
	  treeview_create_and_fill_model_rootsubg (treestore, child, sg);
	  spn = splay_tree_successor (subg->sp_sg, spn->key);
	}

    }

  return;
}

/* */
static GtkTreeModel *
treeview_create_and_fill_model (void)
{
  GtkTreeStore *treestore = NULL;
  GtkTreeIter toplevel;		/* = ? */
  splay_tree_node spn = (splay_tree_node) 0;
  struct usubg *sg = (struct usubg *) 0;
  /* elements are nodes, edges and subgraphs */
  treestore = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_POINTER);
  if (splay_tree_has_data (sp_parsednl))
    {
      gtk_tree_store_append (treestore, &toplevel, NULL);
      gtk_tree_store_set (treestore, &toplevel, 0, "Nodes", 1, NULL, 2, NULL, 3, NULL, -1);
      treeview_create_and_fill_model_rootnodes (treestore, toplevel);
    }

  if (splay_tree_has_data (sp_parsedel))
    {
      gtk_tree_store_append (treestore, &toplevel, NULL);
      gtk_tree_store_set (treestore, &toplevel, 0, "Edges", 1, NULL, 2, NULL, 3, NULL, -1);
      treeview_create_and_fill_model_rootedges (treestore, toplevel);
    }

  if (splay_tree_has_data (sp_parsedsgl))
    {
      /* */
      gtk_tree_store_append (treestore, &toplevel, NULL);
      gtk_tree_store_set (treestore, &toplevel, 0, "Subgraphs", 1, NULL, 2, NULL, 3, NULL, -1);

      /* scan the subgraphs in root graph */
      spn = splay_tree_min (sp_parsedsgl);

      while (spn)
	{
	  sg = (struct usubg *) spn->value;
	  /* if in root graph */
	  if (sg->rootedon == NULL)
	    {
	      treeview_create_and_fill_model_rootsubg (treestore, toplevel, sg);
	    }

	  spn = splay_tree_successor (sp_parsedsgl, spn->key);
	}

    }

  return (GTK_TREE_MODEL (treestore));
}

/* */
static void
treeview_create_view_and_modell (GtkWidget * view)
{
  GtkTreeViewColumn *col = NULL;
  GtkCellRenderer *renderer = NULL;
  GtkTreeModel *model = NULL;
  const char *title = NULL;
  title = "Graph tree view";
  col = gtk_tree_view_column_new ();
  gtk_tree_view_column_set_title (col, title);
  gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
  renderer = gtk_cell_renderer_text_new ();
  gtk_tree_view_column_pack_start (col, renderer, TRUE);
  gtk_tree_view_column_add_attribute (col, renderer, "text", 0);
  model = treeview_create_and_fill_model ();
  gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);
  g_object_unref (model);
  return;
}

/* */
void
on_treeview_window_destroy (GtkWidget * widget, gpointer data)
{
  if (widget)
    {
    }
  if (data)
    {
    }

  if (treeviewtext_view)
    {
      gtk_widget_destroy (treeviewtext_view);
      treeviewtext_view = NULL;
    }

  if (treeview_window)
    {
      gtk_widget_destroy (treeview_window);
      treeview_window = NULL;
    }

  return;
}

/* show treeview window with the input graph data */
void
on_top_level_window_treeview (GtkWidget * widget, gpointer data)
{
  GtkWidget *view = NULL;
  GtkTreeSelection *selection = NULL;
  GtkWidget *vbox = NULL;
  GtkWidget *hbox = NULL;
  GtkWidget *statusbar = NULL;
  GtkWidget *scrollview = NULL;
  GtkWidget *treeviewtext_scroll = NULL;
  if (widget)
    {
    }

  if (data)
    {
    }

  /* check if there is node data to draw */
  if (drawnldata == NULL)
    {
      return;
    }

  /* only one 1 tree view window at once */
  if (treeview_window)
    {
      return;
    }

  /* create new window */
  treeview_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  /* center on screen */
  gtk_window_set_position (GTK_WINDOW (treeview_window), GTK_WIN_POS_CENTER);
  gtk_window_set_title (GTK_WINDOW (treeview_window), (char *) "Treeview");
  /* try to get this (x,y) size (450,300) */
  gtk_widget_set_size_request (treeview_window, 450, 300);
#if GTK_HAVE_API_VERSION_2
  vbox = gtk_vbox_new ( /* homogeneous */ FALSE,
		       /* spacing */ 2);
  gtk_widget_show (vbox);
  gtk_container_add (GTK_CONTAINER (treeview_window), vbox);
#endif
#if GTK_HAVE_API_VERSION_3
  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL,
		      /* spacing */ 2);
  gtk_widget_show (vbox);
  gtk_container_add (GTK_CONTAINER (treeview_window), vbox);
#endif
  /* add next area to the vbox1 */
#if GTK_HAVE_API_VERSION_2
  hbox = gtk_hbox_new ( /* homogeneous */ FALSE,
		       /* spacing */ 0);
  gtk_box_pack_start ( /* box */ GTK_BOX (vbox),
		      /* child */ hbox,
		      /* expand */ TRUE, /* fill */ TRUE,	/* padding */
		      PACKPADDING);
  gtk_widget_show (hbox);
#endif
#if GTK_HAVE_API_VERSION_3
  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
		      /* spacing */ 0);
  gtk_box_pack_start ( /* box */ GTK_BOX (vbox),
		      /* child */ hbox,
		      /* expand */ TRUE, /* fill */ TRUE,	/* padding */
		      PACKPADDING);
  gtk_widget_show (hbox);
#endif
  /* create treeview itself */
  view = gtk_tree_view_new ();
  /* add the data to the treeview model */
  treeview_create_view_and_modell (view);
  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
  /* add scrollbars to treeview */
  scrollview = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (scrollview), view);
  gtk_box_pack_start (GTK_BOX (hbox), scrollview, TRUE, TRUE, 1);
  /* Create a multiline text widget. */
  treeviewtext_view = gtk_text_view_new ();
  /* help text cannot be edited in the window */
  gtk_text_view_set_editable (GTK_TEXT_VIEW (treeviewtext_view), FALSE);
  /* wrap by word */
  gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (treeviewtext_view), GTK_WRAP_WORD);
  /* add scroll to the text area */
  treeviewtext_scroll = gtk_scrolled_window_new (NULL, NULL);
  gtk_container_add (GTK_CONTAINER (treeviewtext_scroll), treeviewtext_view);
  gtk_box_pack_start (GTK_BOX (hbox), treeviewtext_scroll, TRUE, TRUE, 1);
  /* selected item status line */
  statusbar = gtk_statusbar_new ();
  gtk_box_pack_start (GTK_BOX (vbox), statusbar, FALSE, TRUE, 1);
  g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (treeview_on_changed), statusbar);
  g_signal_connect (G_OBJECT (treeview_window), "destroy", G_CALLBACK (on_treeview_window_destroy), NULL);
  gtk_widget_show_all (treeview_window);
  return;
}

/***zz10***/

/* end */
